P3854 题解

· · 题解

看到题解大多是用圆方树做的,圆方树是什么,于是蒟蒻来发一篇用点双的题解。

题目描述

给定一张无向连通图,多组询问,每组询问给出点 X,Y,D ,在删除点 D 之后,判断点 X,Y 是否连通。

Solution

对于每组询问,我们分情况讨论。

$\bullet$ 如果点 $X$ 和 $Y$ 处于同一个点双之内,那么不管删除哪一个点, $X$ 和 $Y$ 显然还是联通的,输出 no。 $\bullet$ 最后一种情况,就是 $X$ 和 $Y$ 不在同一个点双之内并且 $D$ 点是割点,这时我们先缩点,此时这张图变成一棵树,设 $tx$ 为 $X$ 所在的点双,$ty$ 为 $Y$ 所在的点双,我们只需判断 $D$ 点是否在 $tx$ 到 $ty$ 的路径上就可以了,在则输出 yes,否则输出 no。 如何判断树上的一个点 $D$ 是否在另两个点 $X$ 和 $Y$ 的路径上呢,我们只需要判断 $dist(X,D)$ 加上 $dist(Y,D)$ 是否等于 $dist(X,Y)$ 就可以了。 ## Code ```cpp #include<bits/stdc++.h> using namespace std; const int N=2e4+100,M=1e5+100; struct edge{int y,pre;}a[M<<1];int alen,last[N]; void ins(int x,int y){alen++;a[alen]={y,last[x]};last[x]=alen;} int dfn[N],low[N],id,dcc; int sta[N],top,vis[N],New[N],c[N]; vector<int> q[N]; void tarjan(int x){ dfn[x]=low[x]=++id; sta[++top]=x; int cnt=0; for(int k=last[x];k;k=a[k].pre){ int y=a[k].y; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(dfn[x]<=low[y]){ cnt++; if(x>1||cnt>1)vis[x]=1; int tmp;dcc++; do{ tmp=sta[top--]; q[dcc].push_back(tmp); }while(tmp!=y); q[dcc].push_back(x); } } else low[x]=min(low[x],dfn[y]); } } int dep[N],par[N][21]; void prepare(int x,int fa){ dep[x]=dep[fa]+1;par[x][0]=fa; for(int i=1;i<=19;i++)par[x][i]=par[par[x][i-1]][i-1]; for(int k=last[x];k;k=a[k].pre){ int y=a[k].y; if(y!=fa)prepare(y,x); } } int LCA(int x,int y){ if(dep[x]<dep[y])swap(x,y); for(int i=19;i>=0;i--){ if(dep[par[x][i]]>=dep[y])x=par[x][i]; } if(x==y)return y; for(int i=19;i>=0;i--){ if(par[x][i]!=par[y][i]){ x=par[x][i],y=par[y][i]; } } return par[x][0]; } int dist(int x,int y,int lca){ return dep[x]+dep[y]-dep[lca]*2; } int main(){ int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } tarjan(1); int sum=dcc; for(int i=1;i<=n;i++){ if(vis[i])New[i]=++sum; } alen=0;memset(last,0,sizeof(last)); for(int i=1;i<=dcc;i++){ for(int j=0;j<q[i].size();j++){ int x=q[i][j]; if(vis[x])ins(New[x],i),ins(i,New[x]); else c[x]=i; } } prepare(1,0); int q;scanf("%d",&q); while(q--){ int x,y,d;scanf("%d%d%d",&x,&y,&d); x=vis[x]?New[x]:c[x]; y=vis[y]?New[y]:c[y]; if(x==y||!vis[d]){ puts("no"); continue; } d=New[d]; int lca1=LCA(x,y),lca2=LCA(x,d),lca3=LCA(y,d); if(dist(x,y,lca1)==dist(x,d,lca2)+dist(y,d,lca3))puts("yes"); else puts("no"); } return 0; } ```