首页 > 其他分享 >P8943 Deception Point 题解

P8943 Deception Point 题解

时间:2023-05-25 22:02:25浏览次数:33  
标签:Deception int 题解 len edge re P8943 tp cutx

Description

题目给的很详细了。

Solution

首先 \(n\) 个点 \(n\) 条边,我们很容易就想到基环树(比正常的树多了一条边,形成了一个环),不会也没关系,这题跟基环树其实关系不大。

首先,我们可以发现题目中说明了这个环不是一个四元及以下的环,这代表着如果 \(A\) 提前进入了这个环,那么他就可以和 \(B\) 周旋,这样 \(B\) 就永远都抓不到 \(A\) ;相反的,如果 \(B\) 赶在 \(A\) 之前就把 \(A\) 通往环内的那个点就封死了,那么 \(A\) 就只能静待被抓了。

想到这里其实思路就很明了了,我们需要预处理出这些东西:

  • 求出这个环;

  • 求出每个不在环上的点到环的距离以及最初到环上的哪个点;

  • 求出环内点与点之间的距离。

由于赛前几天一直在学习边双,降智了,所以找环我用的边双做的(,其实也可以用拓扑等方法来解决;

对于第二个问题,我们 \(O(n)\) 枚举每一条边,如果出现了点 \(x\) 在环内点 \(y\) 不在环内的情况,我们从 \(y\) 开始进行广搜给 \(y\) 延伸出来的子树打上标记。

对于第三个问题,我们随便断掉环上的一条边,这样形成的就是一条链,我们在链上以断的那条边的其中一个端点为起点再进行一次广搜,处理出环上每个点到这个端点的距离,那么最后环上两个点 \(x,y\) 的最短距离就是 \(\min(\lvert len_x-len_y \rvert,size- \lvert len_x-len_y \rvert)\),其中 \(size\) 表示的是这个环的大小。

由此可知,总复杂度是一个线性的,可以通过。

Code

#include<bits/stdc++.h>
//define int long long
#define ll long long
#define next nxt
#define re register
#define il inline
const int N = 4e5 + 5;
using namespace std;
int max(int x,int y){return x > y ? x : y;}
int min(int x,int y){return x < y ? x : y;}

int n,q,u,v,cnt,tot,idx,ans,k,cutx,cuty;
int low[N],dfn[N],stk[N],belong[N],len[N];
struct Node{
	int tp,dep;//tp表示这个不在环上的点通过哪个点进入环,以及到环的距离
}f[N];
vector <int> vec[N];
struct node{
	int u,v,next;
}edge[N<<1]; int head[N],num_edge;

il int read()
{
	int f=0,s=0;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) f |= (ch=='-');
	for(; isdigit(ch);ch=getchar()) s = (s<<1) + (s<<3) + (ch^48);
	return f ? -s : s;
}

il void add(int from,int to)
{
	edge[++num_edge] = (node){from,to,head[from]};
	head[from] = num_edge;
}

il void tarjan(int x,int in_edge)//边双缩点
{
	dfn[x] = low[x] = ++tot;
	stk[++idx] = x;
	for(re int i=head[x];i;i=edge[i].next)
	{
		int y = edge[i].v;
		if(!dfn[y])
		{
			tarjan(y,i);
			low[x] = min(low[x],low[y]);
		}
		else if(i != (in_edge^1)) low[x] = min(low[x],dfn[y]);
	}
	if(dfn[x] == low[x])
	{
		++cnt;
		while(x != stk[idx+1])
		{
			vec[cnt].push_back(stk[idx]);
			belong[stk[idx]] = cnt;
			idx--;
		}
	}
}

il void bfs(int tp,int x,int dep)//求不在环上的点从哪个点入环,路径长度是多少
{
	f[x] = (Node){tp,dep};
	queue <int> q;
	q.push(x);
	while(!q.empty())
	{
		u = q.front(); q.pop();
		for(re int i=head[u];i;i=edge[i].next)
		{
			v = edge[i].v;
			if(v == tp) continue;
			if(!f[v].dep)
			{
				f[v].dep = f[u].dep + 1 , f[v].tp = tp;
				q.push(v);
			}
		}
	}
}

il void circle()//求断边后链上路径长
{
	memset(len , -1 , sizeof len);
	len[cutx] = 0;
	queue <int> q;
	q.push(cutx);
	while(!q.empty())
	{
		u = q.front(); q.pop();
		for(re int i=head[u];i;i=edge[i].next)
		{
			v = edge[i].v;
			if((u == cutx && v == cuty) || (v == cutx && u == cuty)) continue;
			if(belong[v] != k) continue;
			if(len[v] == -1)
			{
				len[v] = len[u] + 1;
				q.push(v);
			}
		}
	}
}

signed main()
{
	n = read() , q = read();
	num_edge = 1;
	for(re int i=1;i<=n;i++)
	{
		u = read() , v = read();
		add(u,v) , add(v,u);
	}
	tarjan(1,1);//边双缩点找环
	for(re int i=1;i<=cnt;i++) if(vec[i].size() > 1) { k = i; break; }//找哪个是环,步骤一
	for(re int i=2;i<=num_edge;i++)
	{
		u = edge[i].u , v = edge[i].v;
		if(belong[u] == belong[v]) { cutx = u , cuty = v ; continue; }//随便找一条在环上的边
		if(belong[u] == k && belong[v] != k) bfs(u,v,1);//一个在环上一个不在环上,进行步骤二
	}
	circle();//步骤三
	int siz = vec[k].size() , disu , disv;
	while(q--)
	{
		u = read() , v = read();
		if(belong[u] == k) { cout << "Survive" << "\n"; continue; }//原本就在环里那直接跑了
		disu = f[u].dep;//计算路径长度
		if(belong[v] == k) disv = min(abs(len[f[u].tp]-len[v]),siz-abs(len[f[u].tp]-len[v]));//B要拦截的距离就是B到环的距离B的tp和A的tp之间的距离
		else disv = f[v].dep + min(abs(len[f[u].tp]-len[f[v].tp]),siz-abs(len[f[u].tp]-len[f[v].tp]));
		if(disu < disv) cout << "Survive" << "\n";
		else cout << "Deception" << "\n";
	}
	return 0;
}

标签:Deception,int,题解,len,edge,re,P8943,tp,cutx
From: https://www.cnblogs.com/bloodstalk/p/17433084.html

相关文章

  • [ABC287D] Match or Not 题解
    Description翻译给的很明白了,就是让你判断\(S\)串的前\(x(0\leqx\leq|T|)\)个字符和后\(|T|-x\)个字符组成的字符串和\(T\)串是否相等,其中问号能代替所有字母。Solution很有意思的一道题。首先我们可以知道,如果前\(i-1\)位不能匹配的话,那么第\(i\)位不管它本......
  • P5446 [THUPC2018]绿绿和串串 题解
    Description给定一个串\(S\),要求串\(S\)是串\(R\)经过多次翻转后的前缀。问有多少种初始长度的串\(R\)。串\(R\)翻转的定义是将前\(|R|-1\)个字符倒序排列后,插入到串的最后。如\(\mathrm{aaa}\)翻转后得到\(\mathrm{abcdcba}\)。Solution我们先设以\(i\)为......
  • CF1139E Maximize Mex 题解
    Description\(n\)个学生,\(m\)个社团。每个学生有一个能力值,且仅属于一个社团。这\(d\)天内,每天从\(m\)个社团中选人,使得选出的人的能力值的\(\text{mex}\)最大。每天会有一个人在选人之前退团。\(d,m\leqn\leq5000\)Solution巧妙建图题。首先,我们可以很显然的......
  • P8081 [COCI2011-2012#4] ZIMA 题解
    题意给定一个长度为\(n\)的序列。当连续\(T\)天温度都小于\(0\)时,则称这\(T\)天为一个冰期,冰期来临之前的\(2T\)天都被标记为警示状态.特殊地,如果一个冰期最长,那么它的前\(3T\)天会被标记为警示状态。如果有多个冰期最长,选一个。思路模拟预处理出每个冰期的长......
  • AT2395 [ARC071C] TrBBnsformBBtion 题解
    题目大意有两个只包含\(A\)和\(B\)的字符串,给出两种操作A可以变为BB,B可以变为A;AAA可以消去,BBB也可以消去。思路找规律。这里我们以A为主,将B全部变为A。因为可以无限次操作,那么就代表如果两个字符串可以相等,那么他们就一定能够经过转化后变成同一个字......
  • CF714B Filya and Homework 题解
    题意给定一个长度为\(n\)的数组。我们可以给一些数加上一个\(x\),也可以减去一个\(x\),也可以不加也不减。问:是否存在一个数\(x\),使得这个数组里各个数都相等。思路一道思维题首先考虑,在这个数组中,相同的元素,我们一定是给它做相同的操作,否则一定不相等,根据这个思想,......
  • UVA1514 Piece it together 题解
    图论题还是在于建图题意给定一个长度为\(n\timesm\)的网格图,有的地方是白方块,有的是黑方块,有的啥也没用。给你如下四种\(L\)形方块,询问是否存在方法,让这些方块正好就是给出的图的形状。$L$形方块如下思路二分图首先我们要想,为什么需要二分图:若能拼成,那么就说......
  • SP15637 Mr Youngs Picture Permutations 题解
    题意给定一个最多有\(5\)排的一个队伍,每一个位置对应一个同学,给定总人数和第\(i\)排要站\(n_i\)个人。要求每行左边的同学身高要大于右边的,每列从上往下要从大到小。问:满足要求的一共有多少种方案。思路DP首先考虑,在这个题目中,有用的状态有每列最后的人的高度,每行......
  • P8584 探索未知 题解
    题意给你\(n\)个分数,每个分数后面跟着一个操作符\(op\),如果为\(1\)就是加上这个分数,是\(2\)就减去。初始时是\(0\),询问\(n\)次操作后最后的分数是多少,化成最简分数。特殊地,如果最后是个整数,直接以整数的形式输出。思路模拟考试的时候一看就想到了[NOIP2020]......
  • P8587 新的家乡 题解
    题意给定\(n\)个高度分别为\(h_i\)的柱子,两个柱子能合并成一个\(h_i+h_j\)的新柱子,每根柱子至多被使用一次。询问最多能建出多少根高度相同的柱子,并且最优答案下柱子的高度有多少种情况。\(1\leqn\leq10^6\),\(1\leqh_i\leq3\times10^3\)。思路爆搜!首先我们......