ACM-ICPC2018 青岛赛区网络预赛-B- Red Black Tree

本文介绍了一种结合树形DP与区间查询RMQ技术的算法,用于解决特定类型的最优化问题。通过预处理和动态规划,该算法能够在一棵带权树上找到一组顶点,使得改变至多一个顶点颜色后的最大代价最小化,展示了算法在复杂树结构中的应用。
题目描述
BaoBao has just found a rooted tree with n vertices and (n-1) weighted edges in his backyard. Among the vertices, m of them are red, while the others are black. The root of the tree is vertex 1 and it’s a red vertex.
Let’s define the cost of a red vertex to be 0, and the cost of a black vertex to be the distance between this vertex and its nearest red ancestor.
Recall that 
  • The length of a path on the tree is the sum of the weights of the edges in this path.
  • The distance between two vertices is the length of the shortest path on the tree to go from one vertex to the other.
  • Vertex u is the ancestor of vertex v if it lies on the shortest path between vertex v and the root of the tree (which is vertex 1 in this problem).
As BaoBao is bored, he decides to play q games with the tree. For the i-th game, BaoBao will select ki vertices vi,1, vi,2, . . . , vi,ki on the tree and try to minimize the maximum cost of these ki vertices by changing at most one vertex on the tree to a red vertex.
Note that
  • BaoBao is free to change any vertex among all the n vertices to a red vertex, NOT necessary among the ki vertiecs whose maximum cost he tries to minimize.
  • All the q games are independent. That is to say, the tree BaoBao plays with in each game is always the initial given tree, NOT the tree modified during the last game by changing at most one vertex.
Please help BaoBao calculate the smallest possible maximum cost of the given ki vertices in each game after changing at most one vertex to a red vertex.
输入
There are multiple test cases. The first line of the input is an integer T, indicating the number of test cases. For each test case:
The first line contains three integers n, m and q (2≤m≤n≤105, 1≤q≤2×105), indicating the size of the tree, the number of red vertices and the number of games.
The second line contains m integers r1, r2, . . . , rm (1 = r1 < r2 <...< rm≤n), indicating the red vertices.
The following (n-1) lines each contains three integers ui, vi and wi (1≤ui, vi≤n, 1≤wi≤109),indicating an edge with weight wi connecting vertex ui and vi in the tree.
For the following q lines, the i-th line will first contain an integer ki (1≤ki≤n). Then ki integers vi,1, vi,2, . . . , vi,ki follow (1≤vi,1 < vi,2 < ... < vi,ki≤n), indicating the vertices whose maximum cost BaoBao has to minimize.
It’s guaranteed that the sum of n in all test cases will not exceed 106, and the sum of ki in all test cases will not exceed 2×106.
输出
For each test case output q lines each containing one integer, indicating the smallest possible maximum cost of the ki vertices given in each game after changing at most one vertex in the tree to a red vertex.
样例输入
2
12 2 4
1 9
1 2 1
2 3 4
3 4 3
3 5 2
2 6 2
6 7 1
6 8 2
2 9 5
9 10 2
9 11 3
1 12 10
3 3 7 8
4 4 5 7 8
4 7 8 10 11
3 4 5 12
3 2 3
1 2
1 2 1
1 3 1
1 1
2 1 2
3 1 2 3
样例输出
4
5
3
8
0
0
0
提示
The first sample test case is shown above. Let’s denote C(v) as the cost of vertex v.
For the 1st game, the best choice is to make vertex 2 red, so that C(3) = 4, C(7) = 3 and C(8) = 4. So the answer is 4.
For the 2nd game, the best choice is to make vertex 3 red, so that C(4) = 3, C(5) = 2, C(7) = 4 and C(8) = 5. So the answer is 5.
For the 3rd game, the best choice is to make vertex 6 red, so that C(7) = 1, C(8) = 2, C(10) = 2 and C(11) = 3. So the answer is 3.
For the 4th game, the best choice is to make vertex 12 red, so that C(4) = 8, C(5) = 7 and C(12) = 0.
So the answer is 8.
 
二分总是过不了呀呀呀呀
自闭了啊啊啊啊 
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200000+10;
int T,n,m,q,cnt,tot;
bool red[N];
int last[N],pos[N],f[N],rmq[N],mm[N],dp[N][20],a[N];
ll cost[N],cost_t[N];
struct tree{
    int v,w,nex;
}t[N];
bool cmp(int a,int b)
{
    return cost_t[a]>cost_t[b];
}
void add(int x,int y,int z)
{
    cnt++;
    t[cnt].v=y;
    t[cnt].nex=last[x];
    last[x]=cnt;
    t[cnt].w=z;
}
void dfs(int x,int fa,int deep,ll dis,ll dis1)
{
    if (red[x]) dis1=0;
    cost[x]=dis; cost_t[x]=dis1;
    pos[x]=tot; f[tot]=x; rmq[tot++]=deep;
    for (int i=last[x];i;i=t[i].nex)
    {
        if (t[i].v==fa) continue;
        dfs(t[i].v,x,deep+1,dis+t[i].w,dis1+t[i].w);
        f[tot]=x;
        rmq[tot++]=deep;
    }
}
void ST(int n)
{
    mm[0]=-1;
    for (int i=1;i<=n;i++)
    {
        mm[i]=((i&(i-1))==0) ? mm[i-1]+1:mm[i-1];
        dp[i][0]=i;
    }
    for (int j=1;j<=mm[n];j++)
        for (int i=1;i+(1<<j)-1<=n;i++)
        dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]] ? dp[i][j-1] : dp[i+(1<<(j-1))][j-1];
}
int query(int a,int b)
{
    a=pos[a]; b=pos[b];
    if (a>b) swap(a,b);
    int k=mm[b-a+1];
    int ret=rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]] ? dp[a][k] : dp[b-(1<<k)+1][k];
    return f[ret];
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        int x,y,z,k;
        cnt=0; tot=1;
        memset(red,0,sizeof(red));
        memset(last,0, sizeof(last));
  
        scanf("%d%d%d",&n,&m,&q);
        for (int i=1;i<=m;i++)
        {
            scanf("%d",&x);
            red[x]=true;
        }
        for (int i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z); add(y,x,z);
        }
         
        cost[1]=cost_t[1]=cost_t[n+1]=0;
        dfs(1,-1,1,0,0);
        ST(tot-1);
  
        while (q--)
        {
            scanf("%d",&k);
            for (int i=1;i<=k;i++) scanf("%d",&a[i]);
             
            sort(a+1,a+1+k,cmp);  a[k+1]=n+1;
             
            ll ans=cost_t[a[2]],lon,maxx=0;
            int fa=a[1];
            for (int i=2;i<=k;i++)
            {
                int new_fa=query(fa,a[i]);
                int dep1=rmq[pos[fa]],dep2=rmq[pos[new_fa]];
                if (dep2<dep1) maxx+=cost[fa]-cost[new_fa];
  
                lon=min(cost_t[a[i]],cost[a[i]]-cost[new_fa]);
                maxx=max(maxx,lon);
  
                fa=new_fa;
                ans=min(ans,max(maxx,cost_t[a[i+1]]));
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/tetew/p/9688364.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值