「清华集训2017」榕树之心

「清华集训2017」榕树之心

<br>c++

“已经快是严冬了,榕树的叶子还没落呢……”git

“榕树是常绿树,是看不到明显的落叶季节的……”spa

“唉……想不到已经七年了呢。榕树仍是当年的榕树,你却不是当年的你了……”code

“其实又有什么是一成不变的呢,榕树常绿,翠绿树冠的宏观永恒,是由无数细小树叶的荣枯更迭组成的。在时间的流逝中一切都在不断变化着呢……”get

“但你看这榕树,日日如此,季季如此,年年如此,仿佛亘古不变般,盘根错节,郁郁葱葱。我在想,或许成为一棵树更好吧,任时间从枝叶间流过,我只守这一片绿荫就好。”it

“榕树当然长久,但在这无限的时光里,终归是要湮灭于尘土的。与其像榕树通常,植根于一方泥土中感觉年复一年的四季更替。倒不如在有限的时间里看过尽量多的世界吧。再说了,榕树虽生长缓慢,却依旧会在每一年春天抽出一根新的枝条去向外探索的呢……”class

“真的吗,榕树在她漫长的一辈子里,就是这样往外一步步探索的吗?”移动

“毕竟就算树冠看起来一成不变,榕树也会随着时间周期变化,春天到了天然就是生长的时候了,她也应当作出对应的表现吧……”di

“相比于对季节更替作出本能的生长,我倒宁愿相信,榕树有一颗活跃的的,探索的心。”时间

“其实榕树是有心的,榕树刚刚种下的时候,心就在根的地方发芽了。之后每一年春天榕树长出新枝条的时候,心就会向着新枝条的方向移动一点,这样就能更靠近外面的世界了。你看这头顶上的枝条,纵横交错,其实心已经在这枝杈间,移动了数十载了呢……”

“哇,也就是说,这密密麻麻的树杈中的某个地方,藏着这棵榕树的心吗?”

“没错,但是要知道它在哪,就得另花一番功夫了……”

“呀,这时候想一想,一株树仍是不如一我的好……好比你,要是这样贴上去的话,就能听到跳动的声音呢……”

<br>

解题思路

先判断最后可否到 $1$ 怎么作,考虑每个节点不一样儿子子树的两次操做会相互抵消,显然移回当前节点剩下最少操做的方案必定是剩下若干来自最大儿子子树的点,那么只须要尽量消除最大儿子子树便可。

令 $tot[u]$ 表示从 $u$ 子树内从 $u$ 出发最后回到 $u$ ,最少剩余的生长操做数量。 $$ \begin{cases} tot[u] = sz[u] \bmod 2, & sz[u]-sz[v]-1 \geq tot[v]+1 \ tot[u]=tot[v]+1-(sz[u]-tot[v]-1), &otherwise \end{cases} $$ 其中 $v$ 是 $u$ 的全部儿子中子树大小最大的那个,考虑若是最大儿子内部消完剩下的东西能够直接用其它儿子的子树消掉,那么答案就是 $sz[u] \bmod 2$ ,不然每个其它儿子子树内的点都能和最大儿子剩下的东西消一下,直接减便可。

考虑一次性要求全部点的可行性怎么作,考虑在移到 $u$ 时当前已经完成的操做必定是 $1-u$ 的路径以及路径上挂着的一些子树,事实上必定存在一种策略可让这些挂着的子树互相消除,那么问题就转化成和判断 $1$ 的可行性相似的问题,把 $1-x$ 路压缩起来当作新根便可。

code

/*program by mangoyang*/ 
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int ch = 0, f = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
const int N = 1000005;
vector<int> g[N];
int sz[N], ms[N], tot[N], ans[N], n;
inline void dfs(int u, int fa){
	sz[u] = 1;
	for(int i = 0; i < (int) g[u].size(); i++){
		int v = g[u][i];
		if(v == fa) continue;
		dfs(v, u), sz[u] += sz[v];
		if(sz[v] > sz[ms[u]]) ms[u] = v;
	}
	if(!ms[u]) return; 
	if(tot[ms[u]] + 1 <= sz[u] - sz[ms[u]] - 1)
		tot[u] = ((sz[u] - 1) & 1);
	else tot[u] = tot[ms[u]] + 1 - (sz[u] - sz[ms[u]] - 1);
}
inline void dfs2(int u, int fa, int anc, int add){
	int ms2 = 0;
	if(u > 1){
		int size = sz[u] + add, mx;
		if(sz[ms[u]] > sz[anc]) mx = ms[u]; else mx = anc;
		if(tot[mx] + 1 <= size - sz[mx] - 1) ans[u] = ((size - 1) & 1);
		else ans[u] = tot[mx] + 1 - (size - sz[mx] - 1);
	}
	for(int i = 0; i < (int) g[u].size(); i++)
		if(g[u][i] != fa && g[u][i] != ms[u] && sz[g[u][i]] > sz[ms2]) ms2 = g[u][i];
	for(int i = 0; i < (int) g[u].size(); i++){
		int v = g[u][i], tmp = 0;
		if(v == fa) continue;
		if(v == ms[u]) tmp = sz[ms2] > sz[anc] ? ms2 : anc;
		else tmp = sz[ms[u]] > sz[anc] ? ms[u] : anc;
		dfs2(v, u, tmp, add + sz[u] - sz[v] - 1);
	}
}
int main(){
	int T, type; read(type), read(T); while(T--){
		read(n);
		for(int i = 1; i <= n; i++) g[i].clear(), sz[i] = tot[i] = ms[i] = ans[i] = 0;
		for(int i = 1, x, y; i < n; i++){
			read(x), read(y);
			g[x].push_back(y), g[y].push_back(x);
		}
		dfs(1, 0);
		ans[1] = tot[1];
		dfs2(1, 0, 0, 0);
		if(type == 3){ printf("%d\n", !ans[1]); continue; }
		for(int i = 1; i <= n; i++) putchar(!ans[i] ?'1':'0');
		puts("");
	}
	return 0;
}
相关文章
相关标签/搜索