[HDU2874]Connections between cities
阿新 • • 發佈:2017-07-10
true scan == pac %d names std head put
題目大意:給你n個節點的森林(註意不是一棵樹),m條路徑的長度,c個詢問,要你回答每個詢問兩個點i和j的最短距離,或者回答沒有連接。
數據範圍:2<=n<=10000,0<=m<10000,1<=c<=1000000
解題思路:對於每個節點,求出其到根的距離a[i],然後求兩點的最近公共祖先LCA,最後的答案為$a[i]+a[j]-2*a[LCA(i,j)]$。
我用的是Tarjan算法。
註意此題可能出現兩個相同點的情況,需要註意一些細節,或者特判。
C++ Code:
#include<cstdio> #include<cstring> using namespace std; int n,m,c,cnt=0,cntq=0,head[10002],headq[1000002],fa[10002],a[10002]={0}; bool vis[10002],all[10002]; struct edge{ int to,dist,next; }e[20004]; struct Q{ int to,next; }q[2000004]; int ans[1000002]; void addedge(int from,int to,int dist){ cnt++; e[cnt].to=to; e[cnt].dist=dist; e[cnt].next=head[from]; head[from]=cnt; cnt++; e[cnt].to=from; e[cnt].dist=dist; e[cnt].next=head[to]; head[to]=cnt; } int dad(int x){ return(fa[x]==x)?(x):(fa[x]=dad(fa[x])); } void addq(int x,int y){ cntq++; q[cntq].to=y; q[cntq].next=headq[x]; headq[x]=cntq; cntq++; q[cntq].to=x; q[cntq].next=headq[y]; headq[y]=cntq; } void lca(int root,int pre){ fa[root]=root; for(int i=head[root];i;i=e[i].next){ int p=e[i].to; if(p!=pre){ a[p]=a[root]+e[i].dist; lca(p,root); } } vis[root]=all[root]=true; for(int i=headq[root];i;i=q[i].next){ int p=q[i].to; if(vis[p]){ int LCA=dad(p); ans[(i+1)/2]=a[root]+a[p]-a[LCA]*2; } } fa[root]=pre; } int main(){ while(scanf("%d%d%d",&n,&m,&c)!=EOF){ cnt=cntq=0; memset(a,0,sizeof(a)); memset(fa,0,sizeof(fa)); memset(head,0,sizeof(head)); memset(headq,0,sizeof(headq)); memset(e,0,sizeof(e)); memset(q,0,sizeof(q)); memset(ans,-1,sizeof(ans)); memset(all,0,sizeof(all)); for(int i=1;i<=m;i++){ int from,to,dist; scanf("%d%d%d",&from,&to,&dist); addedge(from,to,dist); } for(int i=1;i<=c;i++){ int x,y; scanf("%d%d",&x,&y); addq(x,y); } for(int i=1;i<=n;i++) if(!all[i]){ memset(vis,0,sizeof(vis)); lca(i,0); } for(int i=1;i<=c;i++) if(ans[i]==-1)puts("Not connected");else printf("%d\n",ans[i]); } return 0; }
[HDU2874]Connections between cities