Red Black Tree ZOJ Problem Set - 4048

版权声明:小白一个,欢迎各位指错。 https://blog.csdn.net/qq_36424540/article/details/82800258

BaoBao has just found a rooted tree with vertices and weighted edges in his backyard. Among the vertices, 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 is the ancestor of vertex if it lies on the shortest path between vertex and the root of the tree (which is vertex 1 in this problem).

As BaoBao is bored, he decides to play games with the tree. For the -th game, BaoBao will select vertices on the tree and try to minimize the maximum cost of these 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 vertices to a red vertex, NOT necessary among the vertiecs whose maximum cost he tries to minimize.

  • All the 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 vertices in each game after changing at most one vertex to a red vertex.

Input

There are multiple test cases. The first line of the input is an integer , indicating the number of test cases. For each test case:

The first line contains three integers , and (, ), indicating the size of the tree, the number of red vertices and the number of games.

The second line contains integers (), indicating the red vertices.

The following lines each contains three integers , and (, ), indicating an edge with weight connecting vertex and in the tree.

For the following lines, the -th line will first contain an integer (). Then integers follow (), indicating the vertices whose maximum cost BaoBao has to minimize.

It's guaranteed that the sum of in all test cases will not exceed , and the sum of in all test cases will not exceed .

Output

For each test case output lines each containing one integer, indicating the smallest possible maximum cost of the vertices given in each game after changing at most one vertex in the tree to a red vertex.

Sample Input

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

Sample Output

4
5
3
8
0
0
0

Hint

当时不知道怎样来出来,总想着一个一个的来处理,不知道怎样批处理,能批处理,一般都是有序的

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=b-1;i>=a;--i)

const int N=2e5+10;
const LL INF=1e18;

struct Edge {
    int u,v,nt;
    LL w;
    Edge(int _u=0,int _v=0,int _nt=0,LL _w=0)
    {
        u=_u,v=_v,nt=_nt,w=_w;
    }
} edge[N*2];
int head[N],cnt;
void add_edge(int u,int v,LL w)
{
    edge[cnt]=Edge(u,v,head[u],w);
    head[u]=cnt++;
}


int tot,seq[N*2],R[N*2],dep[N],in[N],out[N];
LL dis[N],d[N];

int red[N];
void dfs(int u,int f)
{
    if(red[u]) d[u]=0;
    seq[++tot]=u;
    R[tot]=dep[u];
    in[u]=tot;
    for(int i=head[u]; i!=-1; i=edge[i].nt) {
        Edge& e=edge[i];
        if(e.v==f)continue;
        dep[e.v]=dep[e.u]+1;
        dis[e.v]=dis[e.u]+e.w;
        d[e.v]=d[u]+e.w;
        dfs(e.v,u);
        seq[++tot]=u;
        R[tot]=dep[u];
    }
    out[u]=tot;
}

int dp[N][20],Log[N];
void RMQ(int n)
{
    rep(i,0,n+1)dp[i][0]=i;
    for(int j=1; (1<<j)<=n; ++j) {
        for(int i=0; i+(1<<j)-1<=n; ++i) {
            int a=dp[i][j-1],b=dp[i+(1<<j-1)][j-1];
            dp[i][j]=R[a]<R[b]?a:b;
        }
    }
}

int LCA(int a,int b)
{
    a=in[a],b=in[b];
    if(a>b)swap(a,b);//一定记得加上
    int t=b-a+1;
    t=Log[t];
    int p1=dp[a][t],p2=dp[b-(1<<t)+1][t];
    return R[p1]<R[p2]?seq[p1]:seq[p2];
}


int q[N];

bool cmp(int a,int b)
{
    return d[a]>d[b];
}
/*
这个距离可不可以,我们不需要关心后面<x的是不是可以更小,所以我们直接到 >x的第一位置就好了,后面肯定符合我们的范围
还有就是如果不断的往右走,那么左边的距离就会变大,我们还是把眼光放大一点,直接求出来所有的超范围的祖先,然后找到一个最大值就好了
*/
bool check(LL x,int K)
{
    int rt=q[0];
    rep(i,0,K) {
        if(d[q[i]]<=x)break;
        rt=LCA(rt,q[i]);
        //printf("i:%d rt:%d q[i]:%d\n",i,rt,q[i]);
    }

    LL mx=0;
    rep(i,0,K) {
        if(d[q[i]]<=x)break;
        LL db=dis[rt]+dis[q[i]]-2*dis[rt];
        //printf("x:%lld %d da:%lld  rt:%d db:%lld\n",x,q[i],da,rt,db);
        mx=max(mx,db);
        //printf("mx:%lld\n",mx);
    }
    return mx<=x;
}

void solve(int K)
{
    sort(q,q+K,cmp);
    LL l=0,r=d[q[0]],mid,ans=INF;
    while(l<=r) {
        mid=(l+r)>>1;
        if(check(mid,K)) {
            ans=mid;
            r=mid-1;
        } else {
            l=mid+1;
        }
    }
    printf("%lld\n",ans);
}

int main()
{
    Log[1]=0;
    rep(i,2,N)Log[i]=Log[i/2]+1;

    int T;
    scanf("%d",&T);
    while(T--) {
        int n,m,Q;
        scanf("%d %d %d",&n,&m,&Q);

        fill(red,red+n+1,0);
        cnt=0;
        fill(head,head+n+1,-1);

        rep(i,0,m) {
            int t;
            scanf("%d",&t);
            red[t]=1;
        }

        rep(i,0,n-1) {
            int u,v;
            LL w;
            scanf("%d %d %lld",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }

        tot=0;
        dfs(1,0);
        RMQ(tot);

        rep(i,0,Q) {
            int K;
            scanf("%d",&K);
            rep(j,0,K)scanf("%d",&q[j]);
            solve(K);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36424540/article/details/82800258