XJOI网上同步测试DAY14 T3
思路:tarjan把桥找出来,然后缩点,注意这里的缩点是:如果两个点之间的连边不是桥,那么就把他们缩起来,然后用一个lct维护,对于每个询问,如果官道连接的是两个联通块的话,就把他们连起来,否则我们就把u到v的路径全部染色成0
最后只要询问缩点完的S到缩点完的T的路径上有多少是1就是答案了,最后复杂度:O(nlogn)
至于为什么这么做:因为我们要找必经过的边,这不就是桥吗,那我们先预处理出原来图的桥,然后把图转变成树,之后对于官道来说,它只要是连接了两个在同一个联通块里的点,就表明这段路绝对不可能是必经之路,而对于连接两个连通分量的边,那么它就是新的桥啊!因此它要被新建成为lct中的一条边。
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<cstring> struct edge{ int u,v; }e[600005]; int n,m; int tot,go[600005],next[600005],first[600005],Id[600005]; int ch[600005][2],sz,num,sum[600005],w[600005],col[600005],tag[600005]; int dfn[600005],low[600005],pd[600005],vis[600005]; int st[600005],c[600005],belong[600005],fa[600005]; int rev[600005],size[600005]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } void insert(int x,int y,int id){ tot++; go[tot]=y; next[tot]=first[x]; first[x]=tot; Id[tot]=id; } void add(int x,int y,int id){ insert(x,y,id); insert(y,x,id); } void tarjan(int x,int Fa){ dfn[x]=low[x]=++sz; for (int i=first[x];i;i=next[i]) if (Id[i]!=Fa){ int pur=go[i]; if (!dfn[pur]){ tarjan(pur,Id[i]); low[x]=std::min(low[x],low[pur]); if (low[pur]>dfn[x]) pd[Id[i]]=1; }else{ low[x]=std::min(low[x],dfn[pur]); } } } void bfs(int x){ int h=1,t=1;c[1]=x;vis[x]=1;belong[x]=++num; while (h<=t){ int now=c[h++]; for (int i=first[now];i;i=next[i]){ int pur=go[i]; if (pd[Id[i]]||vis[pur]) continue; c[++t]=pur; vis[pur]=1; belong[pur]=num; } } } bool isroot(int x){ return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } void pushdown(int x){ int l=ch[x][0],r=ch[x][1]; if (tag[x]!=0){ int id=(tag[x]==1)?0:1; if (l)tag[l]=tag[x]; if (r)tag[r]=tag[x]; if (l&&w[l]) col[l]=id; if (r&&w[r]) col[r]=id; if (l) sum[l]=size[l]*id; if (r) sum[r]=size[r]*id; tag[x]=0; } if (rev[x]){ rev[l]^=1; rev[r]^=1; rev[x]=0; std::swap(ch[x][0],ch[x][1]); } } void updata(int x){ int l=ch[x][0],r=ch[x][1]; if (w[x]==0){ col[x]=0;sum[x]=0;size[x]=0; if (l) sum[x]+=sum[l],size[x]+=size[l]; if (r) sum[x]+=sum[r],size[x]+=size[r]; return; } sum[x]=col[x];size[x]=1; if (l) sum[x]+=sum[l],size[x]+=size[l]; if (r) sum[x]+=sum[r],size[x]+=size[r]; } void rotate(int x){ int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0;else l=1;r=l^1; if (!isroot(y)){ if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x; } fa[x]=z;fa[y]=x;fa[ch[x][r]]=y; ch[y][l]=ch[x][r];ch[x][r]=y; updata(y);updata(x); } void splay(int x){ int top=1;st[1]=x; for (int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i]; for (int i=top;i;i--) pushdown(st[i]); while (!isroot(x)){ int y=fa[x],z=fa[y]; if (!isroot(y)){ if (ch[y][0]==x^ch[z][0]==y) rotate(x); else rotate(y); } rotate(x); } //updata(x); } void access(int x){ for (int t=0;x;t=x,x=fa[x]){ splay(x); ch[x][1]=t; updata(x); } } void makeroot(int x){ access(x);splay(x);rev[x]^=1; } int find(int x){ access(x);splay(x); while (ch[x][0]) x=ch[x][0]; return x; } void cut(int x,int y){ makeroot(x);access(y);splay(y); ch[y][0]=fa[ch[y][0]]=0; updata(y); } void link(int x,int y){ makeroot(x);fa[x]=y; } int main(){ n=read();m=read(); for (int i=1;i<=m;i++){ e[i].u=read();e[i].v=read(); add(e[i].u,e[i].v,i); } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,0); sz=0;num=0; for (int i=1;i<=n;i++) if (!vis[i]) bfs(i); sz=num; for (int i=1;i<=m;i++) if (belong[e[i].u]!=belong[e[i].v]){ sz++;col[sz]=1;tag[sz]=0;sum[sz]=1;w[sz]=1; size[sz]=1; link(sz,belong[e[i].u]); link(sz,belong[e[i].v]); } int q=read(); while (q--){ int S=read(),T=read(),Num=read(),cnt=0; S=belong[S],T=belong[T]; for (int i=1;i<=Num;i++){ e[i].u=read();e[i].v=read(); e[i].u=belong[e[i].u]; e[i].v=belong[e[i].v]; } for (int i=1;i<=Num;i++){ if (e[i].u==e[i].v) continue; if (find(e[i].u)!=find(e[i].v)){ w[sz+i]=1;sum[sz+i]=1; tag[sz+i]=0;col[sz+i]=1; size[sz+i]=1; link(e[i].u,sz+i); link(e[i].v,sz+i); pd[i]=1; }else{ pd[i]=0; makeroot(e[i].u);access(e[i].v);splay(e[i].v); tag[e[i].v]=1; } } if (find(S)!=find(T)){ puts("-1"); }else{ makeroot(S);access(T);splay(T); printf("%d\n",sum[T]); } for (int i=Num;i>=1;i--){ if (e[i].u==e[i].v) continue; if (pd[i]==1){ cut(e[i].u,sz+i); cut(e[i].v,sz+i); }else{ makeroot(e[i].u);access(e[i].v);splay(e[i].v); tag[e[i].v]=-1; } } } }