[hdu2874]Connections between cities(LCA+并查集)
题意:n棵树,求任意两点的最短距离。
解题关键:并查集判断两点是否位于一棵树上,然后求最短距离即可。此题可以直接对全部区间直接进行st表,因为first数组会将连接的两点的区间表示出来。
1 //#pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<iostream> 8 typedef long long ll; 9 using namespace std; 10 const int maxn=11000; 11 const int maxm=25; 12 int _pow[maxm],m,n; 13 int head[maxn],tot; 14 int ver[maxn*2],depth[maxn*2],first[maxn],rmq[maxn*2][25],id;//5个数组,注意哪个需要乘2 15 ll dis[maxn]; 16 int par[maxn]; 17 inline int read(){ 18 char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar()); 19 int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0'; 20 if(k=='-')x=0-x;return x; 21 } 22 23 struct edge{ 24 int to,w,nxt; 25 }e[maxn*2];//链式前向星建树 26 27 void init(){ 28 memset(head,-1,sizeof head); 29 tot=0; 30 id=0; 31 } 32 33 void add_edge(int u,int v,int w){ 34 e[tot].to=v; 35 e[tot].w=w; 36 e[tot].nxt=head[u]; 37 head[u]=tot++; 38 } 39 40 void dfs(int u,int fa,int dep){ 41 ver[++id]=u;//第i个访问到的结点编号 42 depth[id]=dep;//第i个访问到的结点深度 43 first[u]=id; 44 for(int i=head[u];i!=-1;i=e[i].nxt){ 45 int v=e[i].to; 46 int w=e[i].w; 47 if(v==fa) continue; 48 dis[v]=dis[u]+w;//dis是先序遍历求 49 dfs(v,u,dep+1); 50 ver[++id]=u;//后序遍历,再次访问父节点 51 depth[id]=dep; 52 } 53 } 54 //int KT[maxn*2]; 55 void rmq_init(int n){ 56 //KT[1] = 0; 57 //for(int i = 2; i <= n; i++) 58 // KT[i] = KT[i / 2] + 1; 59 int k=int(log(n)/log(2)); 60 for(int i=1;i<=n;++i) rmq[i][0]=i; 61 for(int j=1;j<=k;++j){ 62 for(int i=1;i+_pow[j]-1<=n;++i){//因为存的是索引 63 int a=rmq[i][j-1],b=rmq[i+_pow[j-1]][j-1]; 64 rmq[i][j]=depth[a]<depth[b]?a:b; 65 } 66 } 67 } 68 69 int rmq_query(int l,int r){ 70 int k=int(log(r-l+1.0)/log(2.0)); 71 int a=rmq[l][k],b=rmq[r-_pow[k]+1][k]; 72 return depth[a]<depth[b]?a:b; 73 }//返回的依然是索引 74 75 int LCA(int u,int v){ 76 int x=first[u],y=first[v]; 77 if(x>y)swap(x,y); 78 int res=rmq_query(x,y); 79 return ver[res]; 80 } 81 82 void init1(){ 83 for(int i=1;i<=n;i++) par[i]=i; 84 } 85 86 int find(int x){ 87 if(par[x]==x) return x; 88 else return par[x]=find(par[x]); 89 } 90 91 void unite(int x,int y){ 92 x=find(x),y=find(y); 93 if(x!=y) par[x]=y; 94 } 95 96 int main(){ 97 for(int i=0;i<maxm;++i) _pow[i]=1<<i; //预处理2^n 98 int t,a,b,c,d; 99 while(scanf("%d%d%d",&n,&m,&d)!=EOF){ 100 init(); 101 init1(); 102 for(int i=0;i<m;++i){ 103 a=read(),b=read(),c=read(); 104 add_edge(a,b,c); 105 add_edge(b,a,c); 106 unite(a,b); 107 } 108 for(int i=1;i<=n;i++){ 109 if(par[i]!=i) continue; 110 dfs(i,-1,0); 111 } 112 rmq_init(2*n-1); 113 for(int i=0;i<d;++i){ 114 a=read();b=read(); 115 if(find(a)!=find(b)){ 116 printf("Not connected\n"); 117 continue; 118 } 119 int ans=LCA(a,b); 120 printf("%lld\n",dis[a]+dis[b]-2*dis[ans]); 121 } 122 } 123 return 0; 124 }