bzoj2286 消耗战
还是虚树的题目啊...
如果只有一个询问,我们这么考虑,可以设dp[x]为只删除x子树内和x到父亲的边,使得x这棵子树内的能源岛屿都与x的父亲不连通的最小花费。
这样如果x本身是能源岛屿,那么dp[x]=fe[x],否则dp[x]=min(fe[x],sum{dp[son[x]]})类似这样。(fe表示父亲边,fe[1]=inf)
那么有了多组询问我们就在虚树上搞这个,需要注意的是虚树上的一条父子边就对应着原树上一条父子链,而权值就是那个父子链的最小值。可以用倍增一起维护掉。
需要注意的是...要用long long啊
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> #include <math.h> #include <set> #include <map> using namespace std; typedef long long ll; int inf=1000000000; ll inf_ll=10000000000000000LL; #define gc getchar() int g_i() { int tmp=0; bool fu=0; char s; while(s=gc,s!='-'&&(s<'0'||s>'9')) ; if(s=='-') fu=1; else tmp=s-'0'; while(s=gc,s>='0'&&s<='9') tmp=tmp*10+s-'0'; if(fu) return -tmp; else return tmp; } #define gi g_i() #define pob #define pc(x) putchar(x) namespace ib {char b[100];} inline void pll(ll x) { if(x==0) {pc(48); return;} if(x<0) {pc('-'); x=-x;} char *s=ib::b; while(x) *(++s)=x%10, x/=10; while(s!=ib::b) pc((*(s--))+48); } #define SZ 1234567 #define D 20 #define _els ;else //real tree namespace rt { int n,fst[SZ],nxt[SZ],vb[SZ],vc[SZ],fa[SZ],dep[SZ],M=0,dfsn[SZ],C=0,sz[SZ],fe[SZ]; int up[SZ][D],mine[SZ][D]; void ad_de(int a,int b,int c) {++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; vc[M]=c;} void adde(int a,int b,int c) {ad_de(a,b,c); ad_de(b,a,c);} void dfs(int p) { dfsn[p]=++C; sz[p]=1; for(int e=fst[p];e;e=nxt[e]) { int b=vb[e]; if(b==fa[p]) continue; fa[b]=up[b][0]=p; fe[b]=vc[e]; mine[b][0]=fe[b]; dep[b]=dep[p]+1; dfs(b); sz[p]+=sz[b]; } } void build() { dfs(1); for(int g=1;g<D;g++) { for(int i=1;i<=n;i++) mine[i][g]=inf; } for(int g=1;g<D;g++) { for(int i=1;i<=n;i++) { if(!up[i][g-1]) continue; up[i][g]=up[up[i][g-1]][g-1]; mine[i][g]=min(mine[i][g-1],mine[up[i][g-1]][g-1]); } } } //jump up (x=fa[x]) until dep[x]=d int jmp(int x,int d) { for(int i=D-1;i>=0;i--) { if(!up[x][i]||dep[up[x][i]]<d)_els x=up[x][i]; } return x; } int gmin(int x,int d) { int minn=inf; for(int i=D-1;i>=0;i--) { if(!up[x][i]||dep[up[x][i]]<d)_els minn=min(minn,mine[x][i]), x=up[x][i]; } return minn; } int lca(int x,int y) { if(dep[x]>dep[y]) swap(x,y); y=jmp(y,dep[x]); if(x==y) return x; for(int i=D-1;i>=0;i--) { if(up[x][i]!=up[y][i]) x=up[x][i], y=up[y][i]; } return fa[x]; } } //virtual tree namespace vt { #define f_ first #define s_ second typedef pair<int,int> pii; //vs: points in vtree int sn,ss[SZ],vn,vs[SZ],stn=0,st[SZ],vfa[SZ],fc[SZ],nc[SZ]; ll f[SZ],vfe[SZ]; bool saf[SZ]; bool cmp_dfsn(int a,int b) {return rt::dfsn[a]<rt::dfsn[b];} ll dp(int x) { if(!saf[x]) return f[x]=vfe[x]; ll sum=0; for(int c=fc[x];c;c=nc[c]) sum+=dp(c); return f[x]=min((ll)vfe[x],sum); } void build() { vn=stn=0; ss[++sn]=1; sort(ss+1,ss+1+sn,cmp_dfsn); for(int i=1;i<=sn;i++) vs[++vn]=ss[i], saf[ss[i]]=i==1; for(int i=1;i<=sn;i++) { int x=ss[i]; if(!stn) {st[++stn]=x; vfa[x]=0; continue;} int lca=rt::lca(x,st[stn]); for(;rt::dep[st[stn]]>rt::dep[lca];--stn) { if(rt::dep[st[stn-1]]<=rt::dep[lca]) vfa[st[stn]]=lca; } if(st[stn]!=lca) { vs[++vn]=lca; saf[lca]=1; vfa[lca]=st[stn]; st[++stn]=lca; } vfa[x]=lca; st[++stn]=x; } sort(vs+1,vs+1+vn,cmp_dfsn); for(int i=1;i<=vn;i++) fc[vs[i]]=0; for(int i=1;i<=vn;i++) { int x=vs[i]; f[x]=inf_ll; if(i>1) vfe[x]=rt::gmin(x,rt::dep[vfa[x]]); else vfe[x]=inf_ll; int f=vfa[x]; nc[x]=fc[f]; fc[f]=x; } pll(dp(1)); pc(10); } } int main() { rt::n=gi; for(int i=1;i<rt::n;i++) { int x=gi,y=gi,z=gi; rt::adde(x,y,z); } rt::build(); int q=gi; while(q--) { vt::sn=gi; for(int i=1;i<=vt::sn;i++) vt::ss[i]=gi; vt::build(); } }