https://vjudge.net/problem/HDU-3686
点双啊,就是在求割顶的时候,另外用一个栈来存一些边
在遍历u点出发的边时,遇到树边或反向边(u,v)就把此边加入栈(可能要记一下边的编号)(但是,如果(u,v)是反过来看的反向边(此时dfn[v]>=dfn[u];实际反向边应该为(v,u))或者反过来的树边(此时k==(last^1))就不能加入)
遇到一个割点,就多一个点双(不考虑因为(fa<0&&child==1)的特判而去掉的割点)
计算(u,v)中遇到割点后,就不断从栈顶弹出边,直到栈顶的边与(u,v)相等,然后再弹出一个边;所有这些弹出的边以及边的两个端点都属于这个点双
先对原图求点双连通分量,求出每条边属于的点双
然后为原图中每一个点双新建一个点,向这个点双内每一个点连边,去掉原图所有边,得到一个新图(实际上是一棵树)
询问两条边a,b时,先找出它们属于的点双对应的点编号x,y,那么答案就是新树上x与y的最短路径中"非点双对应的点"的数量(由于实际是要求这两个点双在原图中的路径间割点数量,而只有割点才可能成为新树中要统计的点)
https://blog.csdn.net/u013480600/article/details/44835827
错误记录:
倍增写错。。。115行少d[anc[x][0]][0]
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 #define CLR(x) memset(x,0,sizeof(x)) 14 #define N 10100 15 #define M 101000 16 typedef pair<pii,int> ppi; 17 struct E{int to,nxt;}; 18 namespace G 19 { 20 E e[M<<1]; 21 int f1[N],ne; 22 int dfn[N],bno[N],dfc,cnt,bn2[M];bool iscut[N]; 23 ppi st[M];int top; 24 vector<int> bcc[N]; 25 //#define D(x) ((x)&2147483646) 26 void clr() 27 { 28 CLR(f1);ne=1; 29 CLR(dfn);CLR(bno);CLR(iscut);CLR(bn2);dfc=cnt=top=0; 30 } 31 void me(int a,int b) 32 { 33 e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne; 34 e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne; 35 } 36 int dfs(int u,int last) 37 { 38 int k,v,lowu=dfn[u]=++dfc,chi=0,lowv;ppi x; 39 for(k=f1[u];k;k=e[k].nxt) 40 { 41 v=e[k].to; 42 if(!dfn[v]) 43 { 44 st[++top]=mp(mp(u,v),k);chi++; 45 lowv=dfs(v,k);lowu=min(lowu,lowv); 46 if(lowv>=dfn[u]) 47 { 48 iscut[u]=1; 49 cnt++;bcc[cnt].clear(); 50 for(;;) 51 { 52 x=st[top--]; 53 if(bno[x.fi.fi]!=cnt) 54 bno[x.fi.fi]=cnt,bcc[cnt].pb(x.fi.fi); 55 if(bno[x.fi.se]!=cnt) 56 bno[x.fi.se]=cnt,bcc[cnt].pb(x.fi.se); 57 bn2[x.se/2]=cnt; 58 if(x.fi.fi==u&&x.fi.se==v) break; 59 } 60 } 61 } 62 else if(dfn[v]<dfn[u]&&k!=(last^1)) 63 { 64 st[++top]=mp(mp(u,v),k); 65 lowu=min(lowu,dfn[v]); 66 } 67 } 68 if(last<0&&chi==1) iscut[u]=0; 69 return lowu; 70 } 71 } 72 int n,m,l2n=18,qq; 73 namespace T 74 { 75 E e[N<<2]; 76 int f1[N<<1],ne; 77 int anc[N<<1][22],d[N<<1][22],dep[N<<1]; 78 //d[i][j]表示i点到其2^j级祖先中(含i,不含祖先),共有几个圆点 79 bool vis[N<<1]; 80 void clr() {CLR(f1);CLR(anc);CLR(vis);CLR(d);CLR(dep);ne=1;} 81 void me(int a,int b) 82 { 83 e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne; 84 e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne; 85 } 86 void dfs(int u,int fa) 87 { 88 int i; 89 vis[u]=1;anc[u][0]=fa;d[u][0]=(u<=n); 90 for(i=1;i<=l2n;i++) 91 { 92 anc[u][i]=anc[anc[u][i-1]][i-1]; 93 d[u][i]=d[u][i-1]+d[anc[u][i-1]][i-1]; 94 } 95 for(int k=f1[u];k;k=e[k].nxt) 96 if(e[k].to!=fa) 97 { 98 dep[e[k].to]=dep[u]+1; 99 dfs(e[k].to,u); 100 } 101 } 102 int ask(int x,int y) 103 { 104 int t,i,ans=0; 105 if(dep[x]<dep[y]) swap(x,y); 106 for(t=dep[x]-dep[y],i=0;t>0;t>>=1,i++) 107 if(t&1) ans+=d[x][i],x=anc[x][i]; 108 if(x==y) return ans; 109 for(i=l2n;i>=0;i--) 110 if(anc[x][i]!=anc[y][i]) 111 { 112 ans+=(d[x][i]+d[y][i]); 113 x=anc[x][i];y=anc[y][i]; 114 } 115 ans+=(d[x][0]+d[y][0]+d[anc[x][0]][0]); 116 return ans; 117 } 118 } 119 int main() 120 { 121 int a,b,i,j; 122 while(1) 123 { 124 G::clr();T::clr(); 125 scanf("%d%d",&n,&m); 126 if(n==0&&m==0) break; 127 for(i=1;i<=m;i++) scanf("%d%d",&a,&b),G::me(a,b); 128 for(i=1;i<=n;i++) if(!G::dfn[i]) G::dfs(i,-1); 129 for(i=1;i<=G::cnt;i++) 130 for(j=0;j<G::bcc[i].size();j++) 131 T::me(n+i,G::bcc[i][j]); 132 for(i=1;i<=n+G::cnt;i++) 133 if(!T::vis[i]) 134 T::dfs(i,0); 135 scanf("%d",&qq); 136 while(qq--) 137 { 138 scanf("%d%d",&a,&b); 139 printf("%d ",T::ask(n+G::bn2[a],n+G::bn2[b])); 140 } 141 } 142 return 0; 143 }