P9386 [THUPC 2023 决赛] 大纲 题解

Description

给定一棵有 n n n 个点的树和数列 a 1 , a 2 … a n a_1,a_2\dots a_n a1,a2an,若 a i = − 1 a_i=-1 ai=1 表示点 i i i 的值不确定,否则点 i i i 的值为非负整数 a i a_i ai

你需要给每一个值不确定的点赋一个非负整数,使得该树满足以下条件:

  • m a x n x maxn_x maxnx 表示点 x x x 的儿子中的最大值,若有多个儿子都为 m a x n x maxn_x maxnx,则 x x x 的值为 m a x n x + 1 maxn_x+1 maxnx+1,否则 x x x m a x n x maxn_x maxnx

问是否存在一组解,存在输出 Reasonable,不存在输出 Unreasonable

Solution

对于一个点 i i i,如果其不确定,则它的初始取值下界为 0,上界为 1e9,如果确定,上界为 a i a_i ai,下界为 a i a_i ai,设 u i u_i ui 表示 i i i 的上界, b i b_i bi 表示 i i i 的下界。

遍历整棵树,对于点 x x x,求出儿子中最大的 b s o n x b_{son_x} bsonx(也就是 m a x n x maxn_x maxnx)以及数量 c n t cnt cnt 和最大的 u s o n x u_{son_x} usonx(设为 m a x x x maxx_x maxxx,其实只有 1e9 a s o n x a_{son_x} asonx 两种,也可以特判是否有不确定的点)。

b s o n x b_{son_x} bsonx 取最大是由 m a x n x maxn_x maxnx 的定义得出的,因为 b b b 是下界,下界取最大才是 m a x n x maxn_x maxnx 啊,这一点很关键,我在这卡了很久。

m a x n x maxn_x maxnx 的定义得出,此时的 m a x n x maxn_x maxnx 还要再加上 [ c n t > 1 ] [cnt>1] [cnt>1]

a x = − 1 a_x=-1 ax=1,更新上下界,满足条件,记住一定要更新上下界,第三个测试点 WA的可能是因为这个。

a x ≠ − 1 a_x\ne-1 ax=1,分类讨论:

  • a x = m a x n x a_x=maxn_x ax=maxnx,满足条件。
  • a x < m a x n x a_x<maxn_x ax<maxnx,下界都比当前大,绝对不满足条件。
  • a x > m a x n x   a n d   a x ≤ m a x x x a_x>maxn_x\ and\ a_x\le maxx_x ax>maxnx and axmaxxx,虽然已经确定的儿子的下界取不到,但是儿子中还有不确定的,将其改为 a x a_x ax 就满足条件了。
  • a x > m a x n x   a n d   a x > m a x x x a_x>maxn_x\ and\ a_x>maxx_x ax>maxnx and ax>maxxx,不满足条件,因为儿子都确定了,所以无法改。

如此 dfs即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define inf 2000000000
int t;
int n;
int tot,head[100010];
int a[100010],b[100010],u[100010];  //a原数值,b下界,u上界
struct edge{
	int to,next;
}e[200010];
void add(int x,int y){
	e[++tot].to=y;
	e[tot].next=head[x];
	head[x]=tot;
}
void clean(){  //多测清空
	tot=0;
	for(int i=1;i<=n;i++){
		head[i]=0;
	}
}
bool dfs(int x,int fax){
	int maxn=-10,cnt=0,maxx=-10;
	for(int i=head[x];i;i=e[i].next){
		int y=e[i].to;
		if(y==fax) continue;
		if(!dfs(y,x)) return 0;   //儿子都已经不满足条件了,可以直接退出
		if(b[y]>maxn){
			maxn=b[y];
			cnt=1;
		}else if(b[y]==maxn){
			cnt++;
		}
		maxx=max(maxx,u[y]);
	}
	if(maxn==-10){  //叶子节点
		return 1;
	}
	maxn=maxn+(cnt>1);
	if(a[x]!=-1){
		if(a[x]<maxn) return 0;
		else if(a[x]==maxn) return 1;
		else if(a[x]<=maxx) return 1;
		else return 0;
	}
	if(a[x]==-1){
		u[x]=maxx;
		b[x]=maxn;
		return 1;
	}
}
void solve(){
	clean();
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]==-1) u[i]=inf,b[i]=0;
		else b[i]=u[i]=a[i];
	}
	for(int i=1;i<n;i++){
		int x,y;
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	if(dfs(1,0)) cout<<"Reasonable"<<endl;
	else cout<<"Unreasonable"<<endl;
}
int main(){
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值