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
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
32
22
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
考虑暴力做法,对于每次询问都做一次DP,复杂度O(nm)
引入新姿势:虚树,考虑sigma(ki)很小,建出虚树:只有用到的点和他们的LCA
然后虚树上DP即可
代码如下:
//MT_LI #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f*=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*f; } struct node{ int x,y,d,next; }a[510000],e[510000];int elen,len,last[510000],first[510000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } void add(int x,int y) { elen++; e[elen].x=x;e[elen].y=y; e[elen].next=first[x];first[x]=elen; } typedef long long ll; ll v[510000]; int id[510000],cnt; int bin[25],f[510000][25],dep[510000]; void dfs(int x,int fa) { id[x]=++cnt; dep[x]=dep[fa]+1;f[x][0]=fa; for(int i=1;bin[i]<=dep[x];i++)f[x][i]=f[f[x][i-1]][i-1]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa) { v[y]=min(v[x],(ll)a[k].d); dfs(y,x); } } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=20;i>=0;i--) if(dep[x]-bin[i]>=dep[y]) x=f[x][i]; if(x==y)return x; for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } bool cmp(int x,int y){return id[x]<id[y];} int k,p[510000],top,sta[510000]; void build() { sort(p+1,p+k+1,cmp); int tp=1; for(int i=2;i<=k;i++)if(LCA(p[tp],p[i])!=p[tp])p[++tp]=p[i]; k=tp; top=0;sta[++top]=1; for(int i=1;i<=k;i++) { int lca=LCA(p[i],sta[top]); while(1) { if(dep[lca]>=dep[sta[top-1]]) { if(lca!=sta[top])add(lca,sta[top]); top--; if(lca!=sta[top])sta[++top]=lca; break; } add(sta[top-1],sta[top]);top--; } if(p[i]!=sta[top])sta[++top]=p[i]; } top--; while(top){add(sta[top],sta[top+1]);top--;} } ll dp[510000]; void treedp(int x) { ll ans=0;dp[x]=v[x]; for(int k=first[x];k;k=e[k].next) { int y=e[k].y; treedp(y);ans+=dp[y]; } first[x]=0; if(ans)dp[x]=min(dp[x],ans); } int main() { bin[0]=1;for(int i=1;i<=24;i++)bin[i]=bin[i-1]<<1; int n=read(); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { int x,y,d; x=read();y=read();d=read(); ins(x,y,d);ins(y,x,d); } cnt=0;dep[1]=1;v[1]=1ll<<60;dfs(1,0); int m=read(); while(m--) { k=read(); for(int i=1;i<=k;i++)p[i]=read(); elen=0;build();treedp(1); printf("%lld\n",dp[1]); } return 0; }
The deepest love I think,later than apart,I will live as you like