首页 > 其他分享 >CF963B Destruction of a Tree 题解

CF963B Destruction of a Tree 题解

时间:2023-10-12 22:34:19浏览次数:37  
标签:CF963B 删除 int 题解 Tree tdx ck1 vec 节点

CF963B Destruction of a Tree 题解

  洛谷题目链接

  这里提供一个较为朴素的 DP 想法。

题意简述

  给定一棵树,节点个数不超过 \(2 \times 10^5\),每次可以删掉度数为偶数的点。问最后能不能删完;能删完给出删除方案。

思路分析

  首先可以随便选一个点作为根。

  其次,我们考虑在一棵子树的删除情况,我们令根节点为 \(u\),它的直接儿子为 \(v_1,v_2 \dots v_k\)。考虑根节点的删除情况,以及删除时需要参考什么东西。我们发现,根节点删除分为两种情况:1.它的父节点被删除了,也就是这颗子树没有(根节点的)“支上去”的那条边;2.它的父节点还没删除,我就删除根节点。此时是有“支上去”的那条边的。

  于是,我们令 \(f_{u,t} ,t \in \{0,1\}\),\(f_{u,0}\) 表示没有“支上去”的那条边的时候,是否可以删除;\(f_{u,1}\) 表示有“支上去”的那条边的时候,是否可以删除。根据定义, \(f_{u,t} \in \{0,1\}\) ,即状态表示的是“不可以”或者“可以”。

  我们考虑子树内如何合理安排删除。我们假设我们现在已经知道了所有 \(v_i,(1 \le i \le k)\) 的 \(f_{v_i,0}\) 和 \(f_{v_i,1}\) 结果。首先,如果存在 \(f_{v_i,0} = 0\) 且 \(f_{v_i,1} = 0\),那么显然无论如何安排删除顺序,也不能保证删除成功。

  接下来我们分析如何安排删除顺序。我们发现,对于 \(f_{v_i,0} = 0\) 且 \(f_{v_i,1} = 1\) 的子节点,应当先删掉它所在的那颗子树(因为要保留 \(u\) 到 \(v_i\) 的那条边的时候才能删)。对于 \(f_{v_i,0} = 1\) 且 \(f_{v_i,1} = 0\) 的节点,我们必须在删掉 \(u\) 之后删。对于\(f_{v_i,0} = 1\) 且 \(f_{v_i,1} = 1\) 的节点,随便安排。

  然后我们考虑根节点如何删除。我们发现,如果删掉前面必须删的那些点后,根节点剩下的边是偶数条,那就删掉,然后 \(f_{u,0} \gets 1\) 即可。但是这里就有一个问题,假如说我们剩奇数条边的时候,我们可以再先删掉一个 \(f_{v_i,0} = 1\) 且 \(f_{v_i,1} = 1\) 的节点来使得度数变成偶数。于是这里要再判断一下。

  奇数的时候同理,注意“支上去”的边也是连在根节点上的,所以对应的,\(f_{u,1} \gets 1\)。

  具体实现的时候,我们不妨把一个点的子节点按照 \(f_{v_i,0} = 0\) 且 \(f_{v_i,1} = 1\)的节点在前面,\(f_{v_i,0} = 1\) 且 \(f_{v_i,1} = 1\)的节点在中间,\(f_{v_i,0} = 1\) 且 \(f_{v_i,1} = 0\)的节点在后面,以此来排序。

  输出方案的时候,我们可以对于每个点,搜索对应状态(比如根节点是1,从\(f_{1,0}\)开始搜索),再递归下去(对于\(f_{v_i,0} = 1\) 且 \(f_{v_i,1} = 1\)的节点,我们随便钦定一个就行)。所以一共是两遍dfs,第一遍求状态,第二遍根据状态信息推出顺序。第二遍dfs的时候,代码中的分类有所简化,如果不清楚,可以尝试先各类写一遍再简化合并。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 2e5 + 5;

struct edge
{
	int v,next;
}e[N*2];

int head[N];
int cnt;

void adde(int u,int v)
{
	++cnt;
	e[cnt].v =v;
	e[cnt].next = head[u];
	head[u] = cnt;
}

int n;
bool f[N][2];
vector<int> output;

struct node
{
	int idx;
	bool ck0,ck1;
};

bool cmp1(const node xx,const node yy)
{
	if(xx.ck1 != yy.ck1)
		return xx.ck1 > yy.ck1;
	return xx.ck0 < yy.ck0;
}

vector<node> vec[N];
int deg[N];
int tdx[N];

bool dfs(int u,int fa)
{
	bool check = true;
	for(int i = head[u];i != 0;i = e[i].next)
	{
		int v = e[i].v;
		if(v != fa)
		{
			deg[u]++;
			dfs(v,u);
			if(f[v][0] == 0 && f[v][1] == 0)
			{
				check = false;
				break;
			}
			vec[u].push_back({v,f[v][0],f[v][1]});
		}
	}
	if(deg == 0)
	{
		f[u][1] = 0;
		f[u][0] = 1;
	}
	else
	{
		sort(vec[u].begin(),vec[u].end(),cmp1);
		tdx[u] = -1;
		for(int i = 0;i < vec[u].size();i++)
		{
			if(vec[u][i].ck1 == 1 && vec[u][i].ck0 == 0)
			{
				tdx[u] = i;
			}
			else 
			{
				break;
			}
		}
		bool mody = false;
		if(tdx[u]+1 < vec[u].size() && vec[u][tdx[u]+1].ck1 == 1 &&  vec[u][tdx[u]+1].ck1 == 0)
		{
			mody = true;
		}
		if((deg[u]-(tdx[u]+1))%2 == 0)
		{
			f[u][0] = 1;
			if(mody)
				f[u][1] = 1;
		}
		else
		{
			f[u][1] = 1;
			if(mody)
				f[u][0] = 1;
		}
	}
	return check;
}

void efs(int u,int st)
{
	int i = 0;
	for(;i <= tdx[u];i++)
	{
		efs(vec[u][i].idx,1);
	}
	if(st == 0)
	{
		if((deg[u]-(tdx[u]+1))%2 != 0)
		{
			efs(vec[u][i].idx,1);
			i++;
		}
	}
	else
	{
		if((deg[u]-(tdx[u]+1))%2 != 1)
		{
			efs(vec[u][i].idx,1);
			i++;
		}
	}
	output.push_back(u);
	for(;i < vec[u].size();i++)
	{
		efs(vec[u][i].idx,0);
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n;
	for(int i = 1;i <= n;i++)
	{
		int u;
		cin >> u;
		if(u != 0)
		{
			adde(u,i);
			adde(i,u);
		}
	}
	bool res = dfs(1,0);
	if(res == 0 || f[1][0] == 0)
	{
		cout << "NO\n";
		return 0;
	}
	cout << "YES\n";
	efs(1,0);
	for(int i = 0;i < output.size();i++)
	{
		cout << output[i] << "\n";
	}
	return 0;
}

标签:CF963B,删除,int,题解,Tree,tdx,ck1,vec,节点
From: https://www.cnblogs.com/l-cacherr/p/17760763.html

相关文章

  • ABC214H Collecting 题解
    前言这是一道比较神仙的题目,其后半部分的建图是比较困难想到的,前半部分还是较为容易的。题意现在有一张\(N\)个点\(M\)条边的有向图,每个点有一个点权\(a_i\),现在要找出\(K\)条路径,使得这些路径的并集的点权和尽量大。现在求出点权和。\(N,M\le2\times10^5,k\le10\)题......
  • POD 题解
    考虑每种颜色都只在一条链上出现这个限制。考虑使用随机化\(\text{hash}\),我们对每个点随机一个权值,使得每种颜色所有点异或值为\(0\)。这样一种颜色如果只在一条链上,那对两条链\(\text{hash}\)异或值的贡献就是\(0\),否则就是两个随机值。这样如果存在一个颜色存在于两条......
  • 动态树(Link-Cut Tree)
    算法思想动态树算法用于解决一类树上问题,涉及树边的连接和断开,并借助splay实现高效维护树上路径信息。算法细节见YangZhe的论文代码实现P3690【模板】动态树(LCT)#include<bits/stdc++.h>#definelllonglong#defineilinlineusingnamespacestd;intread(){in......
  • CF938F Erasing Substrings 题解
    ErasingSubstrings一个神奇的想法是设\(f_{i,j}\)表示在位置\([1,i]\)中,我们删去了长度为\(2^k(k\inj)\)的一些串,所能得到的最小字典序。使用二分加哈希可以做到\(O(n^2\log^2n)\),无法承受。发现对于状态\(f_{i,j}\),它已经确定了\(i-j\)位的串,因为所有\(\inj\)......
  • [AGC030F] Permutation and Minimum 题解
    PermutationandMinimum看到300的数据范围,再加上计数题,很容易就往计数DP方向去想。为方便,我们将\(n\)乘二。因为是两个位置取\(\min\),于是我们便想到从小往大把每个数填入序列。于是DP数组第一维的意义便出来了:当前已经填入了前\(i\)小个数。考虑当前填入一个数。这......
  • 洛谷P3576 [POI2014] MRO-Ant colony 题解
    MRO-Antcolony根据下取整除法的性质\((\left\lfloor\dfrac{\left\lfloor\dfrac{x}{y}\right\rfloor}{z}\right\rfloor=\left\lfloor\dfrac{x}{yz}\right\rfloor)\),我们可以反向考虑,即从特殊边开始,计算出从每个叶子到特殊边的路径上,要除以的那个分母是什么。这个可以直接一遍df......
  • 洛谷P3713 [BJOI2017] 机动训练 题解
    机动训练这题的瓶颈,在于把\(a_i^2\)看作\(\sum\limits_{i=1}^{a_i}\sum\limits_{j=1}^{a_i}1\),然后我们就可以看成“两两相同的机动路径都能贡献1”。于是我们设\(f_{x1,y1,x2,y2}\)表示两条起点为\((x1,y1)\)和\((x2,y2)\)的相同路径的数量,然后分别枚举两条路径的方向......
  • [AGC013E] Placing Squares 题解
    PlacingSquares关键是将问题从抽象的“正方形面积”转为具象的形式:一段长度为\(d\)的区间,有两个不同的小球要放进去,则总放置方案就是\(d^2\),且不同的区间间方案是通过乘法原理结合的,刚好是题目中\(\prodd^2\)的形式。于是我们可以设计DP:设\(f_{i,j}\)表示前\(i\)个......
  • 洛谷P3118 [USACO15JAN] Moovie Mooving G 题解
    MoovieMoovingG设\(f[i][S]\)表示在第\(i\)场(注意是场,不是部)电影时,已经看了\(S\)里面的电影是否合法。然后贪心地取\(|S|\)最小的状态保存。光荣MLE了,\(21\%\)。发现当一场电影结束后,无论这一场是在哪里看的都没关系。因此我们设\(f[S]\)表示只看集合\(S\)里......
  • CF908D New Year and Arbitrary Arrangement 题解
    NewYearandArbitraryArrangement思路:期望题果然还是恶心呀!我们设\(f[i][j]\)表示当串中有\(i\)个\(a\)和\(j\)个\(ab\)时的方案数。为了方便,设\(A=\dfrac{P_a}{P_a+P_b},B=\dfrac{P_b}{P_a+P_b}\)。显然,可以这样转移:\[f[i][j]=f[i+1][j]\timesA+f[i][i+j]\ti......