[Luo Gu P2459] SDOI2011 war of attrition

Problem Description

In a war, the battlefield by n islands and bridges consisting of n-1, to ensure that there is only one path up between every two islands. Now, our military has to detect the enemy's headquarters at No. 1 for the island, and they do not have enough energy to maintain the fighting, military victory in sight. Known to have abundant energy on other islands k, in order to prevent the enemy access to energy, some of our military mission is to blow up the bridge, so that the enemy can not reach any energy-rich islands. Due to different materials and different structures of the bridge, the bridge to blow up different have different price, hope our military while meeting targets to minimize total costs.

Investigation department also found that there is a mysterious enemy machine. Even after the army cut off all energy, they can also use that machine. Machine-generated effects will not fix all of our military to blow up the bridge, and will re-random distribution of resources (but you can guarantee that resources are not distributed to No. 1 on the island). But the investigation also found that the department can only use this machine m times, so we just need to complete each task.

Input Format

A first line integer n, represents the number of islands.

Next, n-1 lines of three integers u, v, W, u represents number of islands and the islands bridge number v c is directly linked by a consideration, to ensure that a <= u, v <= n-1 and <= c <= 100000.

N + 1 th row, an integer m, the representative number of the enemy machine can be used.

Next m lines, each an integer ki, on behalf of the i-th, ki islands have rich resources, the next integer k h1, h2, ... hk, represents the number of resource-rich islands.

Output Format

It has m output lines, representing the minimum cost per task.

Sample input

10
1 5 13
1 9 6
2 1 19
2 4 8
2 3 91
5 6 8
7 5 4
7 8 31
10 7 9
3
2 10 6
4 5 7 8 3
3 9 4 6

Sample Output

12
32
22

data range

To 100% of the data, 2 <= n <= 250000, m> = 1, sigma (ki) <= 500000,1 <= ki <= n-1

Resolve

A virtual tree board problem ...... First of all, to consider how to do with dynamic programming. In order to delete the minimum number of edges so that any one point does not communicate with an energy point, obviously, for a point, all points or subtree it is not connected to the point, so that the point or not connected to the parent node. Therefore, a node \ (U \) minimum cost node is generated \ (min (SUM, W (U, V)) \) (where \ (SUM \) represents the cost of the first embodiment, \ (V \) represents \ (u \) of the parent node). A special case is that the node is a node of energy, then for the minimum cost tree sub-tree is the price of the second scheme.

Since the dynamic plan thought well, the following optimization with a virtual tree. The energy of each point and their LCA as the key point, to re-establish a tree structure similar to the original tree, but only retained the key points. This new tree is called a virtual tree. Due to the minimum required, then the right side of the primary virtual tree on the right side of the minimum path between two trees. But this also requires a path between two points, time direct the explosion, there is no way to optimize it?

Considering the virtual tree two adjacent nodes \ (u, v \) and \ (U \) parent \ (F \) , the original tree \ (F \) to \ (V \) path bound through the \ (U \) , then if \ (F \) to \ (U \) the minimum value is less than \ (U \) to \ (V \) minimum, apparently broken \ (w (u, f) \ ) more preferably, otherwise broken \ (w (u, v) \) better. Thus, you can find the answer must be \ (v \) to \ (f \) minimum on. Pushed wide, the father of the right side of a point can be assigned directly to its minimum value on the root path does not affect the answer.

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 500002
using namespace std;
int head[N],ver[2*N],nxt[2*N],l;
int n,m,i,j,d[N],size[N],son[N],fa[N],top[N],dfn[N],k,t,cnt,s[2*N],h[2*N];
long long dis[N],edge[N*2];
bool e[N];
int read()
{
    char c=getchar();
    int w=0;
    while(c<'0'||c>'9') c=getchar();
    while(c<='9'&&c>='0'){
        w=w*10+c-'0';
        c=getchar();
    }
    return w;
}
void insert(int x,int y,long long z)
{
    l++;
    ver[l]=y;
    edge[l]=z;
    nxt[l]=head[x];
    head[x]=l;
}
void dfs1(int x,int pre,int dep)
{
    fa[x]=pre;size[x]=1;
    dfn[x]=++cnt;d[x]=dep;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y!=pre){
            dis[y]=min(dis[x],edge[i]);
            dfs1(y,x,dep+1);
            size[x]+=size[y];
            if(size[y]>size[son[x]]) son[x]=y;
        }
    }
}
void dfs2(int x,int y)
{
    top[x]=y;
    if(son[x]) dfs2(son[x],y);
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(!top[y]) dfs2(y,y);
    }
}
int LCA(int x,int y)
{
    if(x==0||y==0) return 0;
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(d[x]<d[y]) swap(x,y);
    return y;
}
int cmp(const int &x,const int &y)
{
    return dfn[x]<dfn[y];
}
long long dp(int u,int pre)
{
    if(e[u]) return dis[u]; 
    long long sum = 0;
    for(int i = head[u]; i; i = nxt[i]) if(ver[i]!=pre) sum += dp(ver[i],u); 
    return min(sum, dis[u]); 
}
int main()
{
    cin>>n;
    for(i=1;i<n;i++){
        int u,v,w;
        u=read();v=read();w=read();
        insert(u,v,w);insert(v,u,w);
    }
    dis[1]=1LL<<50;
    dfs1(1,0,0);
    dfs2(1,0);
    cin>>m;
    for(i=1;i<=m;i++){
        memset(e,0,sizeof(bool)*(n+5));
        memset(head,0,sizeof(int)*(n+5));
        l=t=0;
        k=read();
        for(j=1;j<=k;j++) h[j]=read(),e[h[j]]=1;
        sort(h+1,h+k+1,cmp);
        for(j=1;j<k;j++) h[j+k]=LCA(h[j],h[j+1]);
        k*=2;h[k]=1;
        sort(h+1,h+k+1,cmp);
        k=unique(h+1,h+k+1)-h-1;
        for(j=1;j<=k;j++){
            while(t&&dfn[s[t]]+size[s[t]]-1<dfn[h[j]]) t--;
            if(t){
                insert(s[t],h[j],dis[h[j]]);
                insert(h[j],s[t],dis[h[j]]);
            }
            s[++t]=h[j];
        }
        printf("%lld\n",dp(1,0));
    }
    return 0;
}
//P.S. 树链剖分找LCA跑的真快......

Guess you like

Origin www.cnblogs.com/LSlzf/p/10987562.html