[bzoj2286] [SDOI2011]消耗戰
阿新 • • 發佈:2019-01-03
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; }