hdu2874 非连通的LCA

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 2 1 3 2 2 4 3 5 2 3 1 4 4 5
 

Sample Output
  
  
Not connected 6
Hint
Hint Huge 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 1000010
using 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值