[arc063e]Integers on a Tree

题目大意

一颗点权树,相邻节点点权差绝对值为1。
现在一些点点权已确定,构造一种方案。

做法

自下而上推出每个节点点权区间范围。
为空则无解,同时如果儿子间对该点奇偶性要求不同也无解。
然后接下来只需自上而下构造,只要和父亲相差1,且点权在区间范围内一定可以合法。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10;
int h[maxn],go[maxn*2],nxt[maxn*2],L[maxn],R[maxn],v[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,tot;
bool czy;
void add(int x,int y){
    go[++tot]=y;
    nxt[tot]=h[x];
    h[x]=tot;
}
void dfs(int x,int y){
    int t=h[x];
    while (t){
        if (go[t]!=y){
            dfs(go[t],x);
            if (!czy) return;
            bz[x]|=bz[go[t]];
        }
        t=nxt[t];
    }
    if (v[x]!=-1) bz[x]=1;
    if (!bz[x]) return;
    int l,r;
    bool gjx=0;
    if (v[x]!=-1){
        gjx=1;
        l=r=v[x];
    }
    t=h[x];
    while (t){
        if (go[t]!=y&&bz[go[t]]){
            if (!gjx){
                gjx=1;
                l=L[go[t]]-1;
                r=R[go[t]]+1;
            }
            else{
                if (R[go[t]]+1<l||L[go[t]]-1>r||l%2!=(L[go[t]]-1)%2){
                    czy=0;
                    return;
                }
                l=max(l,L[go[t]]-1);
                r=min(r,R[go[t]]+1);
            }
        }
        t=nxt[t];
    }
    L[x]=l;R[x]=r;
}
void dg(int x,int y){
    if (x!=1){
        if (!bz[x]) v[x]=v[y]+1;
        else if (L[x]<=v[y]+1&&v[y]+1<=R[x]) v[x]=v[y]+1;
        else v[x]=v[y]-1;
    }
    int t=h[x];
    while (t){
        if (go[t]!=y) dg(go[t],x);
        t=nxt[t];
    }
}
int main(){
    scanf("%d",&n);
    fo(i,1,n-1){
        scanf("%d%d",&j,&k);
        add(j,k);add(k,j);
    }
    fo(i,1,n) v[i]=-1;
    scanf("%d",&m);
    fo(i,1,m){
        scanf("%d%d",&j,&k);
        v[j]=k;
    }
    czy=1;
    dfs(1,0);
    if (!czy){
        printf("No\n");
        return 0;
    }
    printf("Yes\n");
    v[1]=L[1];
    dg(1,0);
    fo(i,1,n) printf("%d\n",v[i]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值