题解 P8943
HYdroKomide · · 题解
题意:
首先,
我们充分发挥人类智慧,想到,树有
思路:
我们知道图里必然有且只有一个环,这个环的大小还大于
我们知道图里只有一个环,所以除了环上以外的点都只能通向环上的一个点。我们称
那么,我们需要知道的,就是
当
于是,预处理这一堆就行啦!
分解步骤:
- 分离出图中的环。
- 对于每个环上的点,遍历其子孙,预处理距离。
- 预处理环上点互相的距离。
当然,如果
其实这个方法冗杂比较多,所以代码显得长。具体可参见注释。
程序如下:
#include<cstdio>
#include<vector>
#include<cmath>
const int N=2e5+1;
using namespace std;
int n,q,fd,f[N],dep[N],cnt,sw[N];
bool vis[N],cir[N];
vector<int>g[N];
void dfs1(int x,int fa){//第一个 dfs,找到所有环上的点并标记
if(vis[x]==true){//如果回到老地方,说明有环了
fd=x;
cir[x]=true;
sw[x]=++cnt;//给环上的点依次打上标记,方便后面查询环上两点的距离
return;
}
vis[x]=true;
int u=g[x].size();
for(int i=0;i<u;i++){
int v=g[x][i];
if(v!=fa)dfs1(v,x);
if(fd!=0){
if(fd==x)fd=0;
if(!cir[x]){
cir[x]=true;//回溯的时候就可以继续打标记
sw[x]=++cnt;
}
break;
}
}
return;
}
void dfs2(int old,int x,int fa){//处理所有非环上点与环的距离(深度)
f[x]=old;//存踏上环的地点
dep[x]=dep[fa]+1;
int u=g[x].size();
for(int i=0;i<u;i++){
int v=g[x][i];
if(!cir[v]&&g[x][i]!=fa)dfs2(old,v,x);
}
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);//vector 连边
}
dfs1(1,0);
dep[0]=-1;
for(int i=1;i<=n;i++)
if(cir[i])//对于所有环上的点,进行第二个 dfs
dfs2(i,i,0);
while(q--){
int x,y;
scanf("%d%d",&x,&y);
int st=f[x],ed=f[y];//踏上环的两地
int len=abs(sw[st]-sw[ed]);//环上两地之间的距离
if(len>cnt/2)len=cnt-len;
if(cir[x]||dep[x]<dep[y]+len)printf("Survive\n");
else printf("Deception\n");
}
return 0;
}