木と整数 / Integers on a Tree AtCoder - 2148

题意

N个节点的一棵树,其中K个节点已有权值,要求在其余N-K个节点上赋权值,使得一条边所连接的两个节点权值的差的绝对值为 1 。
如果可以,输出 Yes 及所有点的权值,如果不行,输出 No 。
1≦N≦10^5 , 1≦K≦N

#分析

显然一条边所连接的两个节点奇偶性不同,可以记录节点的奇偶性,初步判断有无矛盾。
对于相邻节点相差 1 的限制,可以通过已知点的取值范围推出周围的点的取值范围,再同那些点原有的取值范围取交集,若交集为空或取值范围只有一个数时不满足该节点奇偶性,则有矛盾。
可以做两遍DFS求出每个点的取值范围。
第一次通过孩子节点限制父节点的取值,第二次通过父节点限制孩子节点的取值。
如果在DFS中没有发现矛盾,就可以通过取值范围求答案了。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100010
#define MAXM 200010
#define INF 1000000000
int Adj[MAXN],V[MAXM],nxt[MAXM],c;
void AddEdge(int u,int v)
{
    c++;V[c]=v,nxt[c]=Adj[u];
    Adj[u]=c;
}
int L[MAXN],R[MAXN],root,odd[MAXN];
void dfs1(int u,int p)
{
    for(int i=Adj[u];i;i=nxt[i])
    {
        int v=V[i];
        if(v==p) continue;
        dfs1(v,u);
        R[u]=min(R[v]+1,R[u]);
        L[u]=max(L[v]-1,L[u]);
        if(odd[v]!=-1)
        {
            if(odd[u]==-1) odd[u]=!odd[v];
            else if(odd[v]==odd[u])
            {
                printf("No\n");
                exit(0);
            }
        }
    }
}
void dfs2(int u,int p)
{
    if(p)
    {
        R[u]=min(R[u],R[p]+1);
        L[u]=max(L[u],L[p]-1);
        if(odd[u]==-1) odd[u]=!odd[p];
    }
    if(L[u]>R[u]||(L[u]==R[u]&&odd[u]!=(L[u]&1)))
    {
        printf("No\n");
        exit(0);
    }
    for(int i=Adj[u];i;i=nxt[i])
        if(V[i]!=p)
        {
            dfs2(V[i],u);
        }
}
int ans[MAXN];
void GetAns(int u,int p)
{
    if(!p) ans[u]=L[u];
    else
    {
        ans[u]=ans[p]-1;
        if(ans[u]<L[u]) ans[u]+=2;
    }
    for(int i=Adj[u];i;i=nxt[i])
        if(V[i]!=p)
            GetAns(V[i],u);
}
int main()
{
    int n,m,u,v;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        AddEdge(u,v);
        AddEdge(v,u);
    }
    for(int i=1;i<=n;i++)
        L[i]=-INF,R[i]=INF,odd[i]=-1;
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&u,&v);
        root=u;
        odd[u]=(v&1);
        L[u]=R[u]=v;
    }
    dfs1(root,0);
    dfs2(root,0);
    GetAns(root,0);
    printf("Yes\n");
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_41343943/article/details/81380426
今日推荐