hdu2874 非连通的LCA

来源:互联网 发布:mysql怎么存储图片 编辑:程序博客网 时间:2024/06/03 07:28

Connections between cities

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5625    Accepted Submission(s): 1540


Problem Description
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.
 

Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.
 

Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.
 

Sample Input
5 3 21 3 22 4 35 2 31 44 5
 

Sample Output
Not connected6
Hint
HintHuge input, scanf recommended.
 

这里使用离线Tarjan算法,此题数据量极大,很容易MLE,经测试关于询问的结构体只能存三个元素,不能随意,否则MLE。到底存什么?to,next和id,to是为了找到这条边的另一个顶点,next是为了连接,id是为了记录读入询问的编号,这样做可以省去fr和lca,我们在原先Tarjan函数里将求得lca的语句替换成直接计算答案,因此只需开一个ans数组保存结果即可,详见代码。至于不同联通分支是无所谓的,就像dfs搜索连通分支个数一样,每个连通分支结果是互不影响的。

代码:

#include<cstdio>#include<iostream>#include<cstring>#define Maxn 10010#define Maxm 1000010using namespace std;struct edge{    int to,w,next;}p[Maxn<<1],ask[Maxm<<1];int head[Maxn],ah[Maxn];int tot,tot1;void addedge(int a,int b,int c){    p[tot].to=b;    p[tot].w=c;    p[tot].next=head[a];    head[a]=tot++;}void addedge1(int a,int b,int id){    ask[tot1].to=b;    ask[tot1].w=id;    ask[tot1].next=ah[a];    ah[a]=tot1++;}int fa[Maxn];int findset(int x){    return fa[x]==x?x:(fa[x]=findset(fa[x]));}void unionset(int a,int b){    fa[findset(a)]=findset(b);}int vis[Maxn];int anc[Maxn];int dist[Maxn];int ans[Maxm];void LCA(int u,int fa,int id){    anc[u]=u;    for(int i=head[u];i!=-1;i=p[i].next){        int v=p[i].to;        if(fa!=v){            dist[v]=dist[u]+p[i].w;            LCA(v,u,id);            unionset(u,v); //将子树合并到父亲            anc[findset(u)]=u; //维护新集合指向父亲        }    }    vis[u]=id; //设置已访问    for(int i=ah[u];i!=-1;i=ask[i].next){ //处理与u关联的边        int v=ask[i].to;        if(vis[v]==id)//若v已访问,则说明u,v的lca是v所在集合的指向            ans[ask[i].w]=dist[u]+dist[v]-2*dist[anc[findset(v)]];    }}void init(int n){    tot=tot1=0;    memset(head,-1,sizeof head);    memset(ah,-1,sizeof ah);    memset(vis,0,sizeof vis);    memset(ans,-1,sizeof ans);    for(int i=1;i<=n;i++) fa[i]=i;}int main(){    int n,m,a,b,w,c;    while(cin>>n>>m>>c){        init(n);        for(int i=0;i<m;i++){            scanf("%d%d%d",&a,&b,&w);            addedge(a,b,w);            addedge(b,a,w);        }        for(int i=1;i<=c;i++){            scanf("%d%d",&a,&b);            addedge1(a,b,i);            addedge1(b,a,i);        }        for(int i=1;i<=n;i++){            if(!vis[i]){                dist[i]=0;                LCA(i,-1,i);            }        }        for(int i=1;i<=c;i++){            if(ans[i]==-1) puts("Not connected");            else printf("%d\n",ans[i]);        }    }return 0;}


0 0