链接:http://acm.hdu.edu.cn/showproblem.php?pid=4297
这道题所给的图是一个森林,每一个子图都必有一个环(因为总边数为n),可以把环当做这棵树的根节点,那么如果两个点不在一棵树上,一定互相不可达,如果在一棵树上,如果两个点在同一棵子树上,那么一起到的点就是LCA,所以要维护森林的LCA,如果不在同一棵子树上,则要到各自的根节点,然后沿着环方向分别判断哪种情况是最优解。
View Code
1 #pragma comment(linker, "/STACK:10240000000,10240000000") 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #define N 500005 7 #define max(a,b) ((a)>(b)?(a):(b)) 8 #define min(a,b) ((a)<(b)?(a):(b)) 9 using namespace std; 10 int nxt[N]; 11 int root[N];//点是否在环上,在环上是环上的第几个点 12 int father[N];//在环上的父节点 13 int num[N];//所在环的节点个数 14 int f[N];//并查集判断是否是在一个树上,并且可以确定环 15 int list[2*N]; 16 int fir[2*N],ti;//rmq解决LCA问题 17 bool used[N]; 18 int deep[2*N]; 19 int n; 20 int head[N],cnt; 21 struct node 22 { 23 int v,next; 24 }; 25 node edge[N];//要加反向边 26 void add(int u,int v) 27 { 28 edge[cnt].v=v,edge[cnt].next=head[u],head[u]=cnt++; 29 } 30 int find(int x) 31 { 32 int r=x; 33 while(r!=f[r]) 34 r=f[r]; 35 int t1; 36 while(x!=f[x]) 37 { 38 t1=f[x]; 39 f[x]=r; 40 x=t1; 41 } 42 return r; 43 } 44 void uni(int x,int y) 45 { 46 int t1=find(x); 47 int t2=find(y); 48 if(t1==t2)//发现一个点和其所要连接的点在一个集合时,说明产生了环 49 { 50 int cnt1=0; 51 int temp=x; 52 do 53 { 54 root[x]=++cnt1; 55 x=nxt[x]; 56 }while(!root[x]); 57 x=temp; 58 num[x]=cnt1; 59 x=nxt[x]; 60 while(x!=temp) 61 { 62 num[x]=cnt1; 63 x=nxt[x]; 64 } 65 } 66 else 67 f[t1]=t2; 68 } 69 int dp[2*N][22]; 70 void makermq() 71 { 72 int i,j; 73 for(i=1;i<ti;i++) 74 dp[i][0]=deep[i]; 75 for(j=1;(1<<j)<ti;j++) 76 { 77 for(i=1;i+(1<<j)-1<ti;i++) 78 dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); 79 } 80 } 81 int rmq(int s,int e) 82 { 83 int k=(int)(log((e-s+1)*1.0)/log(2.0)); 84 return min(dp[s][k],dp[e-(1<<k)+1][k]); 85 } 86 void init() 87 { 88 memset(dp,0x3f,sizeof(dp)); 89 memset(root,0,sizeof(root)); 90 memset(num,0,sizeof(num)); 91 memset(head,-1,sizeof(head)); 92 memset(used,0,sizeof(used)); 93 memset(deep,0,sizeof(deep)); 94 memset(fir,0,sizeof(fir)); 95 memset(father,0,sizeof(father)); 96 memset(list,0,sizeof(list)); 97 cnt=0; 98 ti=1; 99 int i; 100 for(i=1;i<=n;i++) 101 { 102 f[i]=i; 103 } 104 } 105 void dfs(int u,int d,int v) 106 { 107 used[u]=true; 108 if(root[u]) 109 { 110 d=1; 111 v=u; 112 } 113 list[ti]=u; 114 deep[ti]=d; 115 fir[u]=ti; 116 ti++; 117 father[u]=v; 118 int i; 119 for(i=head[u];i>=0;i=edge[i].next) 120 { 121 if(!used[edge[i].v]) 122 { 123 dfs(edge[i].v,d+1,v); 124 list[ti]=u; 125 deep[ti]=d; 126 ti++; 127 } 128 } 129 } 130 int main() 131 { 132 int i,j,m,a,b,temp,t1,t2; 133 while(scanf("%d%d",&n,&m)!=EOF) 134 { 135 init(); 136 for(i=1;i<=n;i++) 137 { 138 scanf("%d",&nxt[i]); 139 add(nxt[i],i); 140 uni(i,nxt[i]); 141 } 142 for(i=1;i<=n;i++) 143 if(root[i]&&(!used[i])) 144 dfs(i,1,i); 145 makermq(); 146 for(i=1;i<=m;i++) 147 { 148 scanf("%d%d",&a,&b); 149 if(find(a)!=find(b)) 150 { 151 printf("-1 -1\n"); 152 continue; 153 } 154 if(father[a]==father[b]) 155 { 156 t1=a,t2=b; 157 if(fir[a]>fir[b])//这里要特别注意 158 { 159 t1=b,t2=a; 160 } 161 temp=rmq(fir[t1],fir[t2]); 162 printf("%d %d\n",deep[fir[a]]-temp,deep[fir[b]]-temp); 163 } 164 else 165 { 166 temp=num[father[a]]; 167 t1=deep[fir[a]]-1; 168 t2=deep[fir[b]]-1; 169 int fa=father[a]; 170 int fb=father[b]; 171 int ans1=t1,ans2=t2; 172 if(root[fa]<root[fb]) 173 { 174 ans1+=(root[fb]-root[fa]); 175 ans2+=(root[fa]+num[fa]-root[fb]); 176 } 177 else 178 { 179 ans1+=(root[fb]+num[fb]-root[fa]); 180 ans2+=(root[fa]-root[fb]); 181 } 182 if(max(ans1,t2)<max(t1,ans2)) 183 { 184 printf("%d %d\n",ans1,t2); 185 } 186 else if(max(ans1,t2)>max(t1,ans2)) 187 { 188 printf("%d %d\n",t1,ans2); 189 } 190 else 191 { 192 if(min(ans1,t2)<min(t1,ans2)) 193 { 194 printf("%d %d\n",ans1,t2); 195 } 196 else if(min(ans1,t2)>min(t1,ans2)) 197 { 198 printf("%d %d\n",t1,ans2); 199 } 200 else 201 { 202 if(ans1>=t2) 203 { 204 printf("%d %d\n",ans1,t2); 205 } 206 else 207 { 208 printf("%d %d\n",t1,ans2); 209 } 210 } 211 } 212 } 213 } 214 } 215 return 0; 216 }