1. 程式人生 > >[bzoj2286] [SDOI2011]消耗戰

[bzoj2286] [SDOI2011]消耗戰

Description

在一場戰爭中,戰場由n個島嶼和n-1個橋樑組成,保證每兩個島嶼間有且僅有一條路徑可達。現在,我軍已經偵查到敵軍的總部在編號為1的島嶼,而且他們已經沒有足夠多的能源維繫戰鬥,我軍勝利在望。已知在其他k個島嶼上有豐富能源,為了防止敵軍獲取能源,我軍的任務是炸燬一些橋樑,使得敵軍不能到達任何能源豐富的島嶼。由於不同橋樑的材質和結構不同,所以炸燬不同的橋樑有不同的代價,我軍希望在滿足目標的同時使得總代價最小。

偵查部門還發現,敵軍有一臺神祕機器。即使我軍切斷所有能源之後,他們也可以用那臺機器。機器產生的效果不僅僅會修復所有我軍炸燬的橋樑,而且會重新隨機資源分佈(但可以保證的是,資源不會分佈到1號島嶼上)。不過偵查部門還發現了這臺機器只能夠使用m次,所以我們只需要把每次任務完成即可。

Input

第一行一個整數n,代表島嶼數量。

接下來n-1行,每行三個整數u,v,w,代表u號島嶼和v號島嶼由一條代價為c的橋樑直接相連,保證1<=u,v<=n且1<=c<=100000。

第n+1行,一個整數m,代表敵方機器能使用的次數。

接下來m行,每行一個整數ki,代表第i次後,有ki個島嶼資源豐富,接下來k個整數h1,h2,…hk,表示資源豐富島嶼的編號。

Output

輸出有m行,分別代表每次任務的最小代價。

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

Solution

虛樹入門題。

注意如果一個點被標記了,它子樹下也有被標記的點,下面的點可以刪掉,然後dp。

#include<bits/stdc++.h>
using namespace std;

#ifdef ONLINE_JUDGE
#define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++)
#endif

namespace fast_IO {
    char buf[1<<21],*p1=buf,*p2=buf;

    template <typename T> inline void read(T &x) {
        x=0;T f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    template <typename T,typename... Args> inline void read(T& x,Args& ...args) {
        read(x),read(args...);
    }

    char buf2[1<<21],a[80];int p,p3=-1;

    inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;}
    template <typename T> inline void write(T x) {
        if(p3>(1<<20)) flush();
        if(x<0) buf2[++p3]='-',x=-x;
        do {a[++p]=x%10+48;} while(x/=10);
        do {buf2[++p3]=a[p];} while(--p);
        buf2[++p3]='\n';flush();
    }
    template <typename T,typename... Args> inline void write(T x,Args ...args) {
        write(x),write(args...);
    }
}

using fast_IO :: read;
using fast_IO :: write;
using fast_IO :: flush;

#define ll long long 

const int maxn = 2.5e5+10;
const int inf = 1e9;

int mn[maxn],dfn[maxn],n,sz[maxn];
ll f[maxn];

struct Normal_Tree {
    int head[maxn],tot,dfn_cnt,f[maxn][20],dep[maxn];
    struct edge{int to,nxt,w;}e[maxn<<1];
    void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
    void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
    void dfs(int x,int fa) {
        dfn[x]=++dfn_cnt;f[x][0]=fa;dep[x]=dep[fa]+1;sz[x]=1;
        for(int i=1;i<=17;i++) f[x][i]=f[f[x][i-1]][i-1];
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=fa) mn[e[i].to]=min(mn[x],e[i].w),dfs(e[i].to,x),sz[x]+=sz[e[i].to];
    }
    int lca(int x,int y) {
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=17;~i;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
        for(int i=17;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
}T;

int cmp(int x,int y) {return dfn[x]<dfn[y];}

struct Virtual_Tree {
    int head[maxn],tot,sta[maxn],use[maxn],in[maxn],top,used,a[maxn];
    struct edge{int to,nxt;}e[maxn<<1];
    void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    void ins(int u,int v) {add(u,v),add(v,u);}
    void dfs(int x,int fa) {
        int bo=1;
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=fa) dfs(e[i].to,x),f[x]+=min((ll)mn[e[i].to],f[e[i].to]),bo=0;
        if(bo) f[x]=mn[x];
        //printf("Dfs:%d %d\n",x,f[x]);
    }
    void solve() {
        int k;read(k);top=used=0;
        for(int i=1;i<=k;i++) read(a[i]);
        sort(a+1,a+k+1,cmp);int p=0;
        for(int i=1;i<=k;i++)
            if(dfn[a[i]]>dfn[in[p]]+sz[in[p]]-1) in[++p]=a[i];
        k=p;
        sta[++top]=1;use[++used]=1;
        for(int i=1;i<=k;i++) {
            if(in[i]==1) continue;
            int t=T.lca(in[i],sta[top]),pre=-1;
            while(dfn[sta[top]]>dfn[t]&&dfn[sta[top]]<dfn[t]+sz[t]) {
                if(pre!=-1) ins(sta[top],pre);
                pre=sta[top];use[++used]=sta[top];top--;
            }
            if(pre!=-1) ins(t,pre);
            if(sta[top]!=t) sta[++top]=t;
            sta[++top]=in[i];
        }
        int pre=-1;
        while(top) {
            if(pre!=-1) ins(sta[top],pre);
            pre=sta[top],use[++used]=sta[top];top--;
        }
        dfs(1,0),write(f[1]);
        for(int i=1;i<=used;i++) head[use[i]]=0,f[use[i]]=0;
        tot=0;
    }
}VT;

int main() {
    read(n);
    for(int i=1,x,y,z;i<n;i++) read(x,y,z),T.ins(x,y,z);
    for(int i=1;i<=n;i++) mn[i]=inf,f[i]=0;T.dfs(1,0);mn[1]=0;
    int t;read(t);
    while(t--) VT.solve();
    flush();
    return 0;
}