Gym - 101972B B. Updating the Tree

B. Updating the Tree

time limit per test

1.5 s

memory limit per test

256 MB

input

standard input

output

standard output

A rooted tree is a tree with a countable number of nodes, in which a particular node is distinguished from the others by being the ancestor node of every node of the tree. This node is called the root node.

You are given a rooted tree consisting of n nodes numbered from 1 to n. The root of the tree is node number 1. Each node i has a value viassigned to it.

For each subtree, you must find the minimum number of nodes you must change the value on them to any other value so that the distance between every pair of nodes in that subtree is equal to the absolute difference between the values on them, or say that it is impossible. Can you?

Input

The first line contains an integer T (1 ≤ T ≤ 100) specifying the number of test cases.

The first line of each test case contains an integer n (1 ≤ n ≤ 105), in which n is the number of nodes in the tree. Then a line follow containing n integers v1, ..., vn (1 ≤ vi ≤ 105), in which vi is the value of the ith node.

Then n - 1 lines follow, each line contains two integers ai and bi (1 ≤ ai, bi ≤ n), giving an edge between nodes ai and bi.

Output

For each test case, print a single line containing n space-separated integers x1, ..., xn, in which xi is the answer of the subtree of node i. If an answer does not exist for a subtree, print  - 1.

Example

input

1
2
1 3
1 2

output

1 0

题意:

给你一棵树,这棵树的点都有点权,让你求对于v为根的子树改变最小数量点的点权,使得这棵子树上任意两个点之间的距离等于点权差的绝对值,1为这整棵树的根,如果无论怎么改都无法满足条件输出-1。

思路:

当且仅当以v为根的这棵子树,v这个点只挂不超过2条链时,才能有满足条件的解。因为只有等差数列(一条链)且d为1或者-1才满足条件,超过两条那么这整棵子树无论从哪个角度看都不是一条链。

tips:下面挂着两条链的根,根可以看做是从它的叶子结点到另一个叶子结点这条链上的一个点。

因此我们考虑找出叶子结点,之后往上爬,一直爬到1或者一个下面挂着两条链的祖先,在往上爬的过程当中我们就已经把对于这条链上所有点的答案都统计出来了,往上爬的时候我们会遇到两种情况:

1.爬到v这个点,v的儿子只有一个,如果v≠1那么我们可以再接着往上爬。

2.爬到v这个点,v的儿子有两个,这个时候就需要找下一个叶子结点往上爬,我们需要标记一下v这个点已经爬过了,等到v的另一个叶子结点往上爬遇到v的时候再处理答案。两条链答案的合并直接暴力就行,因为,对于每一个挂着两条链的根,有一条链只会多访问一次。

可以dfs预处理一边把叶子结点push_back到vector中,并且可以直接记录出不符合要求的根。

对于怎么求最少改多少点满足条件这题问题,首先我们可以设定一个值step,v每爬一次就和v的点权相减得到值x(包括叶子结点),之后step自增(d=1)或者自减(d=-1),x出现次数最多的那一组是不需要动它的,我们维护一个递增和递减,答案就是递增和递减当中取一个n-xmax。(n是爬的次数,也就是当前v子树上结点的个数)

上图举个例子:

(截图的时候不小心把小框框截进去了,被盖掉的部分上面是3,2;下面是0,-1)

仔细观察会发现step递增的时候对于x连续相同的一段,val的值也是保持递增的,这样就能维护出来了。

dfs是线性的,爬的过程也是线性的,答案合并也是线性的(忽略map),所以时间复杂度O(能过)。

示例程序:

#include <bits/stdc++.h>
#define LDQ 1000000007
#define QAQ 0x3f3f3f3f
#define INF 1000000000000000000
#define inv2 ((LDQ+1)>>1)
const long double PI=3.14159265358979323846;
using namespace std;
struct jj
{
    int v,next;
}w[200000];
int h[100000],ans[100000],pre[100000],vis[100000],val[100000],subtreesize[100000],numw;
vector<int>ve;
map<int,int>mp,mp1;
void insert(int u,int v)
{
    w[numw].v=v;
    w[numw].next=h[u];
    h[u]=numw++;
}
int dfs(int pos,int fa)
{
    int i,num=0,flag=0;
    pre[pos]=fa;                    //pre存父亲
    ans[pos]=0;                     //ans存答案
    subtreesize[pos]=1;             //subtreesize存放以v为根子树上结点的个数
    for(i=h[pos];i!=-1;i=w[i].next)
    {
        if(w[i].v!=fa)
        {
            num++;                          //链的个数++
            subtreesize[pos]=subtreesize[pos]+dfs(w[i].v,pos);
            if(ans[w[i].v]==-1||ans[w[i].v]==QAQ-1)//如果有儿子不符合要求,自己也不符合要求,如果它的儿子挂着两个链自己也不满足要求
            {
                ans[pos]=-1;
            }
        }
    }
    if(num==0)
    {
        ve.push_back(pos);                  //存叶子结点
    }
    if(ans[pos]!=-1)
    {
        if(num>2)                           //链的个数大于2的
        {
            ans[pos]=-1;
        }
        else if(num==2)                     //链的个数等于2的
        {
            ans[pos]=QAQ-1;
        }
        else                                //它本身或者只有一条链的
        {
            ans[pos]=QAQ;
        }
    }
    return subtreesize[pos];
}
int main()
{
    int t,i,i1,n,u,v,temp,step,step1,flag,pos;
    scanf("%d",&t);
    while(t--)
    {
        numw=0;
        ve.clear();
        scanf("%d",&n);
        for(i=0;n>i;i++)
        {
            scanf("%d",&val[i]);
            h[i]=-1;
            vis[i]=0;
        }
        for(i=1;n>i;i++)
        {
            scanf("%d %d",&u,&v);
            insert(u-1,v-1);
            insert(v-1,u-1);
        }
        subtreesize[0]=dfs(0,-1);                       //dfs预处理
        for(i=0;ve.size()>i;i++)
        {
            v=ve[i];
            vis[v]=1;                                   //vis记录结点有没有被爬过
            mp.clear();
            mp1.clear();
            temp=0;
            step=step1=0;
            while(ans[v]==QAQ&&v!=-1)                               //只爬一条链的情况
            {
                temp=max(temp,++mp[val[v]-step]);                   //用map哈希一下值
                temp=max(temp,++mp1[val[v]-step1]);                 //递增递减两个中选最大
                step++;
                step1--;
                ans[v]=subtreesize[v]-temp;                         //n-xmax
                vis[v]=1;
                v=pre[v];                                           //往上爬
            }
            if(v!=-1&&ans[v]==QAQ-1)                                //遇到挂着两条链的
            {
                if(vis[v]==1)                                       //如果被爬过就合并答案
                {
                    temp=max(temp,++mp[val[v]-step]);
                    temp=max(temp,++mp1[val[v]-step1]);
                    step++;
                    step1--;
                    pos=v;
                    flag=1;
                    while(flag==1)
                    {
                        flag=0;
                        for(i1=h[v];i1!=-1;i1=w[i1].next)
                        {
                            if(pre[v]!=w[i1].v)                     //因为只有一个儿子我就不开son数组了
                            {
                                v=w[i1].v;
                                temp=max(temp,++mp[val[v]-step]);
                                temp=max(temp,++mp1[val[v]-step1]);
                                step++;
                                step1--;
                                flag=1;
                                break;
                            }
                        }
                    }
                    ans[pos]=subtreesize[pos]-temp;
                }
                vis[v]=1;
            }
        }
        for(i=0;n>i;i++)
        {
            if(i!=0)
            {
                printf(" ");
            }
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wandb: Tracking run with wandb version 0.15.5 wandb: W&B syncing is set to `offline` in this directory. wandb: Run `wandb online` or set WANDB_MODE=online to enable cloud syncing. /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/gym/envs/registration.py:556: UserWarning: WARN: The environment Ant-v2 is out of date. You should consider upgrading to version `v4`. f"The environment {id} is out of date. You should consider " Error compiling Cython file: ------------------------------------------------------------ ... See c_warning_callback, which is the C wrapper to the user defined function ''' global py_warning_callback global mju_user_warning py_warning_callback = warn mju_user_warning = c_warning_callback ^ ------------------------------------------------------------ /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx:92:23: Cannot assign type 'void (const char *) except * nogil' to 'void (*)(const char *) noexcept nogil' Error compiling Cython file: ------------------------------------------------------------ ... See c_warning_callback, which is the C wrapper to the user defined function ''' global py_error_callback global mju_user_error py_error_callback = err_callback mju_user_error = c_error_callback ^ ------------------------------------------------------------ /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx:127:21: Cannot assign type 'void (const char *) except * nogil' to 'void (*)(const char *) noexcept nogil' Compiling /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx because it changed. [1/1] Cythonizing /home/zhangmengjie/anaconda3/envs/torch1/lib/python3.7/site-packages/mujoco_py/cymj.pyx wandb: Waiting for W&B process to finish... (failed 1). wandb: You can sync this run to the cloud by running: wandb: wandb sync /home/zhangmengjie/PID/Python/ERL-Re2-main/wandb/offline-run-20230721_165346-awq1hazo wandb: Find logs at: ./wandb/offline-run-20230721_165346-awq1hazo/logs
最新发布
07-22

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值