Loading

AtCoder Regular Contest 063

C,D 还是太简单,不想写题解ww

F 怎么是 Ag 啊,溜了溜了 /fad

怎么这补题记录已经快变成单题题解了啊(

E - Integers on a Tree

给定 \(n\) 个点的树,部分点上有权值,请补全这个树上所有点权,使得每条边连接的两点点权绝对值差为 1。

\(1\le n\le 10^5\)

题解里有老哥给出了非常简洁且离谱的解法:用小根堆把点权存起来,把点挨个拿出来扩展,最后判断合法性即可。

这个东西感觉很对,但正确性不会证,而且这思路没有啥参考意义,就弃了。

先考虑一个简单的合法性判断:两点差的奇偶性和两点距离的奇偶性相同。

这个可以通过二分图染色判断。

考虑如何构造:先任意指定一个节点为根,向下递归。

和我以前写过的 [CF1304C]Air Conditioner 有点类似,我们先不考虑具体的取值,而是考虑取值的区间。

显然,若子节点 \(v\) 的取值范围为 \([l_v,r_v]\),则父节点 \(u\) 的取值范围为 \(\bigcap\limits_{v\in son_u} [l_v-1,r_v+1]\)

若点权已定,则 \(l_u=r_u=a_u\),反之由子节点推过来。

然后从根到叶子构造一下就行,具体方式参考代码。

时间复杂度 \(\mathcal O(n)\)

Code

// Problem: E - Integers on a Tree
// Contest: AtCoder - AtCoder Regular Contest 063
// URL: https://atcoder.jp/contests/arc063/tasks/arc063_c
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back

const int maxn = 1e5 + 5;
int n,res,d[maxn],L[maxn],R[maxn],a[maxn];
bool flag;
std::vector<int> G[maxn];

void dfs(int u,int fa) {
	if(!flag)return ;
	d[u] = d[fa] ^ 1;
	for(auto& v : G[u]) {
		if(v == fa)continue ;
		dfs(v , u);
		L[u] = std::max(L[u] , L[v] - 1);
		R[u] = std::min(R[u] , R[v] + 1);
	}
	if(L[u] > R[u]) {
		flag = false;
		return ;
	}
	if(~ a[u]) {
		if(L[u] > a[u]||R[u] < a[u]) {
			flag = false;
			return ;
		}
		L[u] = R[u] = a[u];
		if(res == -1)res = (a[u] & 1) ^ d[u];
		else if(res != (a[u] & 1) ^ d[u]) {
			flag = false;
			return ;
		}
	}
	return ;
}

void calc(int u,int fa) {
	if(fa)a[u] = (a[fa] - 1 >= L[u]&&a[fa] - 1 <= R[u]) ? a[fa] - 1 : a[fa] + 1;
	else a[u] = L[u];
	for(auto& v : G[u]) {
		if(v == fa)continue ;
		calc(v , u);
	}
	return ;
}

int main() {
	scanf("%d",&n);
	for(int i = 1;i < n;++ i) {
		int u,v;
		scanf("%d %d",&u,&v);
		G[u].pb(v);
		G[v].pb(u);
	}
	memset(a , -1 , sizeof(a));
	memset(L , ~0x3f , sizeof(L));
	memset(R , 0x3f , sizeof(R));
	int Q;
	scanf("%d",&Q);
	while(Q --) {
		int x,y;
		scanf("%d %d",&x,&y);
		a[x] = y;
	}
	
	flag = true;
	res = -1;
	dfs(1 , 0);
	
	if(!flag) {
		puts("No");
		return 0;
	}
	else {
		puts("Yes");
		calc(1 , 0);
		for(int i = 1;i <= n;++ i)
			printf("%d\n",a[i]);
		return 0;
	}
	return 0;
}
posted @ 2022-11-01 16:10  Skylakes  阅读(30)  评论(0)    收藏  举报