Acesrc and Travel

 Acesrc and Travel

时间限制: 1 Sec  内存限制: 128 MB

题目描述

Acesrc is a famous tourist at Nanjing University second to none. During this summer holiday, he, along with Zhang and Liu, is going to travel to Hong Kong. There are n spots in Hong Kong, and n−1 bidirectional sightseeing bus routes connecting these spots. They decide to visit some spots by bus.

However, Zhang and Liu have different preferences for these spots. They respectively set a satisfactory value for each spot. If they visit the ith spot, Zhang will obtain satisfactory value ai, and Liu will obtain bi. Starting with Zhang, they alternately decide the next spot to visit for the sake of fairness. There must be a bus route between the current spot and the next spot to visit. Moreover, they would never like to visit a spot twice. If anyone can't find such a next spot to visit, they have no choice but to end this travel.

Zhang and Liu are both super smart competitive programmers. Either want to maximize the difference between his total satisfactory value and the other's. Now Acesrc wonders, if they both choose optimally, what is the difference between total satisfactory values of Zhang and Liu?

输入

The first line of input consists of a single integer T (1≤T≤30), denoting the number of test cases.

For each test case, the first line contains a single integer n (1≤n≤105), denoting the number of spots. Each of the next two lines contains n integers, a1,a2,⋯,an and b1,b2,⋯,bn (0≤ai,bi≤109), denoting the 
satisfactory value of Zhang and Liu for every spot, respectively. Each of the last n−1 lines contains two integers x,y (1≤x,y≤n,x≠y), denoting a bus route between the xth spot and the yth spot. It is reachable from any spot to any other spot through these bus routes.

It is guaranteed that the sum of n does not exceed 5.01×105.

输出

For each test case, print a single integer in one line, the difference of total satisfactory values if they both choose optimally.

样例输入

1
3
1 1 1
0 2 3
1 2
1 3

样例输出

-1

题意:有两个人轮流在一棵树上选择点,每个点有一个权值,A想让权值和最大,B想让权值和最小,下一次选择的点必须和这次选择的点有直接边连接,且点不能重复选择,A可以选择任意一个点作为初始点,问最后权值和是多少。
思路:考虑DP,但这是一个无根树,于是首先要转化成有根树DP,即首先把1号点作为根节点,然后DP算出:A或者B选择了某一个点,且上一步是从改点的父亲走过来的最优权值和。然后再考虑父亲反向边的DP,即计算出:A或者B选择了某一个点,且下一步是到改点的父亲的最优权值和。则答案就是在所有B选择点时,维护最大值。
总结:无根树DP就是有根树DP加上父亲反向边的DP。

#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
using namespace std;
 
const int N = 6e5+50;
struct ss
{
    int u,v,next;
};
ss edg[N*2];
int head[N],sum_edge=0;
 
void addedge(int u,int v)
{
    edg[sum_edge]=(ss){u,v,head[u]};
    head[u]=sum_edge++;
}
 
long long value[N];
long long ans=0;
long long dp[N][2];
 
 
void init(int n)
{
    for(int i=0;i<=n;i++)
    {
        head[i]=-1;
        dp[i][0]=dp[i][1]=0;
    }
    sum_edge=0;
    ans=LLONG_MIN;
}
 
long long dfs1(int x,int fa,int type)
{
    if(dp[x][type])return dp[x][type];
    long long now= (type==0 ? LLONG_MIN : LLONG_MAX);
 
    for(int i=head[x];i!=-1;i=edg[i].next)
    {
        int v=edg[i].v;
        if(v==fa)continue;
 
        if(type==0)now=max(now,dfs1(v,x,1)+value[x]);
        else
            now=min(now,dfs1(v,x,0)+value[x]);
    }
    return dp[x][type]=((now==LLONG_MAX||now==LLONG_MIN) ? value[x] : now);
}
 
long long dfs(int x,int fa,int type,long long last_ans)
{
   // printf("%d %d %d %lld\n",x,fa,type,last_ans);
    //printf("x=%d,fa=%d : %lld %lld  value[%d]=%lld\n",x,fa,dfs1(x,fa,0),dfs1(x,fa,1),x,value[x]);
    priority_queue<pair<long long,int> >q;
    for(int i=head[x];i!=-1;i=edg[i].next)
    {
        int v=edg[i].v;
        if(v==fa)continue;
 
        if(type==0)q.push(make_pair(-dfs1(v,x,1),v));
        else
            q.push(make_pair(dfs1(v,x,0),v));
 
        if(q.size()>2)q.pop();
    }
 
    pair<long long,int> first;
    pair<long long,int> second;
 
    if(q.size())
    {
       first=q.top();
       q.pop();
      // printf("%lld\n",first.first);
 
        if(q.size())
        {
            second=q.top();
          //  printf("%lld\n",second.first);
            q.pop();
        }
        else
        {
            second=first;
 
            if(x!=1)first=make_pair(LLONG_MAX/2,-1);
            else
                first=make_pair(0,-1);
        }
    }
    else
    {
        if(x!=1)second=make_pair(LLONG_MAX/2,-1);
        else
            second=make_pair(0,-1);
    }
 
    if(type==0)
    {
        for(int i=head[x];i!=-1;i=edg[i].next)
        {
            int v=edg[i].v;
            if(v==fa)continue;
 
            if(v==second.second)dfs(v,x,1,max(last_ans,-first.first)+value[x]);
            else
                dfs(v,x,1,max(last_ans,-second.first)+value[x]);
        }
    }
    else
    {
        ans=max(ans,min(last_ans,second.first)+value[x]);
        for(int i=head[x];i!=-1;i=edg[i].next)
        {
            int v=edg[i].v;
            if(v==fa)continue;
 
            if(v==second.second)dfs(v,x,0,min(last_ans,first.first)+value[x]);
            else
                dfs(v,x,0,min(last_ans,second.first)+value[x]);
        }
    }
}
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        init(n);
 
        for(int i=1;i<=n;i++)
        scanf("%lld",&value[i]);
 
        for(int i=1;i<=n;i++)
        {
            long long a;
            scanf("%lld",&a);
            value[i]-=a;
        }
 
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
 
     /*   if(n<=2)
        {
            long long sum=0;
            for(int i=1;i<=n;i++)sum+=value[i];
            printf("%lld\n",sum);
            continue;
        }*/
 
        dfs(1,-1,0,LLONG_MIN/2);
        dfs(1,-1,1,LLONG_MAX/2);
 
        printf("%lld\n",ans);
    }
    return 0;
}
View Code
posted @ 2019-08-18 10:16  1371767389  阅读(298)  评论(1编辑  收藏  举报