2286: [Sdoi2011]消耗战
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 3108 Solved: 1115
[Submit][Status][Discuss]
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
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
虚树DP。
pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }
建虚树的时候,若在某个点上面有询问点,则这个点就没有用,所以这个点就不用加进虚树了。所以在DP的时候就不用开个bj数组记录哪些点是询问点,因为若一个点是询问点,那么这个点肯定是叶节点,所以就不用开数组记录了。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define maxn 250010 15 #define inf 1999999999999999999ll 16 #define LL long long 17 using namespace std; 18 struct data{ 19 int nex,to; 20 LL w; 21 }e[maxn*2],g[maxn*2]; 22 int head[maxn],edge=0,head1[maxn],edge1=0; 23 int dfn[maxn],a[maxn],deep[maxn],size[maxn]; 24 int f[maxn][20],Stack[maxn]; 25 LL dis[maxn],dp[maxn]; 26 bool bj[maxn]; 27 inline void add(int from,int to,int w){ 28 if(from==to) return; 29 e[++edge].nex=head[from]; 30 e[edge].to=to; 31 e[edge].w=w; 32 head[from]=edge; 33 } 34 inline void link(int from,int to){ 35 if(from==to) return; 36 g[++edge1].nex=head1[from]; 37 g[edge1].to=to; 38 head1[from]=edge1; 39 } 40 int de=0; 41 void dfs(int x,int fa){ 42 ++de; 43 dfn[x]=de; 44 size[x]++; 45 for(int i=head[x];i;i=e[i].nex){ 46 int u=e[i].to; 47 if(u==fa) continue; 48 f[u][0]=x; 49 deep[u]=deep[x]+1; 50 dis[u]=min(dis[x],e[i].w); 51 dfs(u,x); 52 size[x]+=size[u]; 53 } 54 } 55 void DP(int x,int fa){ 56 LL ans=0; 57 dp[x]=dis[x]; 58 for(int i=head1[x];i;i=g[i].nex){ 59 int u=g[i].to; 60 if(u==fa) continue; 61 DP(u,x); 62 ans+=dp[u]; 63 } 64 head1[x]=0; 65 if(!ans) dp[x]=dis[x]; 66 else if(ans<dp[x]) dp[x]=ans; 67 } 68 inline int lca(int x,int y){ 69 if(deep[x]<deep[y]) swap(x,y); 70 for(int i=18;i>=0;i--) 71 if(deep[f[x][i]]>=deep[y]) x=f[x][i]; 72 if(x==y) return x; 73 for(int i=18;i>=0;i--) 74 if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 75 return f[x][0]; 76 } 77 bool cmp(int a,int b){ 78 return dfn[a]<dfn[b]; 79 } 80 inline void build(){ 81 int tot=0,m,top=0,LCA;scanf("%d",&m); 82 for(int i=1;i<=m;i++) scanf("%d",&a[i]); 83 sort(a+1,a+m+1,cmp); 84 a[++tot]=a[1]; 85 for(int i=2;i<=m;i++) if(lca(a[i],a[tot])!=a[tot]) a[++tot]=a[i]; 86 Stack[++top]=1; 87 for(int i=1;i<=tot;i++){ 88 if(top==0){Stack[++top]=a[i];continue;} 89 LCA=lca(Stack[top],a[i]); 90 while(1){ 91 if(deep[Stack[top-1]]<=deep[LCA]){ 92 link(Stack[top],LCA),link(LCA,Stack[top]); 93 top--; 94 if(Stack[top]!=LCA) Stack[++top]=LCA; 95 break; 96 } 97 link(Stack[top],Stack[top-1]),link(Stack[top-1],Stack[top]); 98 top--; 99 } 100 if(Stack[top]!=a[i]) 101 Stack[++top]=a[i]; 102 } 103 while(top>1)link(Stack[top],Stack[top-1]),link(Stack[top-1],Stack[top]),top--; 104 top--; 105 DP(1,0); 106 printf("%lld\n",dp[1]); 107 edge1=0; 108 } 109 int main() 110 { 111 freopen("!.in","r",stdin); 112 freopen("!.out","w",stdout); 113 int n,x,y,z,qes; 114 scanf("%d",&n); 115 for(int i=1;i<n;i++) 116 scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); 117 deep[1]=1,dis[1]=inf; 118 dfs(1,0); 119 for(int i=1;i<=18;i++) 120 for(int j=1;j<=n;j++) 121 f[j][i]=f[f[j][i-1]][i-1]; 122 scanf("%d",&qes); 123 for(int i=1;i<=qes;i++) 124 build(); 125 return 0; 126 }