1 条题解

  • 0
    @ 2025-8-24 22:43:58

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar HYdroKomide
    I hate unfair games.

    搬运于2025-08-24 22:43:58,当前版本为作者最后更新于2023-01-15 22:56:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意:

    首先,nn 个结点、nn 条边的无向图。

    我们充分发挥人类智慧,想到,树有 n1n-1 条边呀!所以这个图就是一棵树加了一条边,组成了一个环,又称基环树。

    思路:

    我们知道图里必然有且只有一个环,这个环的大小还大于 44。所以如果逃离者 AA 在监守者 BB 堵住路之前到达环上的任意一点,就一定能把监守者绕死。

    我们知道图里只有一个环,所以除了环上以外的点都只能通向环上的一个点。我们称 AA 第一次踏上环的地点为 faAfa_A。若 BB 能够抢先,或者与 AA 同时到达 faAfa_A,那么 AA 必输。否则,AA 必胜。

    那么,我们需要知道的,就是 AA 与环的距离 depAdep_AAA 踏上环的位置 faAfa_ABB 与环的距离 depBdep_BBB 踏上环的位置 faBfa_BAA 踏上位置与 BB 踏上位置的距离 dist(faA,faB)dist(fa_A,fa_B)。如果该点在环上,则 depdep 值为 00

    depAdist(faA,faB)+depBdep_A \le dist(fa_A,fa_B)+dep_B,监守者就会堵住门吃掉 AA。反之 AA 可以逃入环中绕杀监守者。

    于是,预处理这一堆就行啦!

    分解步骤:

    1. 分离出图中的环。
    2. 对于每个环上的点,遍历其子孙,预处理距离。
    3. 预处理环上点互相的距离。

    当然,如果 AA 已经在环上,肯定有救,可以先特判但没必要。

    其实这个方法冗杂比较多,所以代码显得长。具体可参见注释。

    程序如下:

    #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;
    }
    

    THE END

    • 1

    信息

    ID
    8226
    时间
    1000ms
    内存
    128MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者