BZOJ 2286 [Sdoi2011]消耗战 虚树
来源:互联网 发布:mac怎么关闭桌面 编辑:程序博客网 时间:2024/05/19 18:45
2286: [Sdoi2011]消耗战
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4152 Solved: 1504
[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
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
Source
Stage2 day2
学习了一下虚树。
简单的说,就是在多次询问时构造一棵点数较少的树,以获得更优的时间和空间。
对于这题,多次树型DP显然可以,但是会超时。
我们可以在每次DP时省去一些无用的点构造虚树,从而使得每次的时间复杂度提升为询问的点数。
#include <cstdio>#include <iostream>#include <string.h>#include <string> #include <map>#include <queue>#include <deque>#include <vector>#include <set>#include <algorithm>#include <math.h>#include <cmath>#include <stack>#include <iomanip>#define mem0(a) memset(a,0,sizeof(a))#define meminf(a) memset(a,0x3f,sizeof(a))using namespace std;typedef long long ll;typedef long double ld;typedef double db;const int maxn=500005,inf=0x3f3f3f3f; const ll llinf=0x3f3f3f3f3f3f3f3f; const ld pi=acos(-1.0L);int head[maxn],h[maxn],in[maxn],a[maxn],dep[maxn],b[maxn];int mfa[maxn][20],st[maxn];ll md[maxn],dp[maxn];bool visit[maxn]; int num,dfn; struct Edge { int from,to,pre; ll dist;};Edge edge[maxn*2],e[maxn*2]; void addedge(int from,int to,ll dist) { edge[num]=(Edge){from,to,head[from],dist}; head[from]=num++; edge[num]=(Edge){to,from,head[to],dist}; head[to]=num++;} void adde(int from,int to) { if (from==to) return; e[num]=(Edge){from,to,h[from]}; h[from]=num++; e[num]=(Edge){to,from,h[to]}; h[to]=num++;} bool cmp(int a,int b) { return in[a]<in[b];} void dfs(int now,ll dist,int fa,int step) { mfa[now][0]=fa;for (int i=1;mfa[now][i-1]!=0;i++)mfa[now][i]=mfa[mfa[now][i-1]][i-1]; visit[now]=1; a[++dfn]=now;dep[now]=step; in[now]=dfn; if (now!=1) md[now]=min(md[fa],dist); else md[now]=llinf; for (int i=head[now];i!=-1;i=edge[i].pre) { int to=edge[i].to; if (!visit[to]) { dfs(to,edge[i].dist,now,step+1); a[++dfn]=now; } } } int findlca(int a,int b) { int x=a,y=b; int i; if (dep[x]>dep[y]) swap(x,y); for (i=18;i>=0;i--) { if (dep[mfa[y][i]]>=dep[x]) y=mfa[y][i]; } if (y==x) return x; for (i=18;i>=0;i--) { if (mfa[y][i]!=mfa[x][i]&&mfa[x][i]!=0&&mfa[y][i]!=0) { x=mfa[x][i];y=mfa[y][i]; } } return mfa[x][0];} void makedp(int now,int fa) { ll sum=0; for (int i=h[now];i!=-1;i=e[i].pre) { int to=e[i].to; if (to!=fa) { makedp(to,now); sum+=dp[to]; } } if (sum==0) sum=llinf; dp[now]=min(md[now],sum); h[now]=-1;} void build() { int n,j,i,k; scanf("%d",&k); for (i=1;i<=k;i++) scanf("%d",&b[i]); sort(b+1,b+k+1,cmp); num=0; n=1; for (i=2;i<=k;i++) if (findlca(b[n],b[i])!=b[n]) b[++n]=b[i]; int top=0; st[++top]=1; for (i=1;i<=n;i++) { int now=b[i],f=findlca(now,st[top]); while (true) { if (dep[f]>=dep[st[top-1]]) { adde(f,st[top--]); if (st[top]!=f) st[++top]=f; break; } adde(st[top-1],st[top]); top--; } if (st[top]!=now) st[++top]=now; } while (--top) adde(st[top],st[top+1]);// for (i=0;i<num;i++) cout << e[i].from << ' ' << e[i].to << endl; makedp(1,0); printf("%lld\n",dp[1]);} int main() { int n,i,x,y,d,q; scanf("%d",&n); num=dfn=0;memset(head,-1,sizeof(head)); for (i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&d); addedge(x,y,(ll)d); } mem0(visit); dfs(1,0,0,1); scanf("%d",&q); memset(h,-1,sizeof(h)); for (i=1;i<=q;i++) build(); return 0;}
阅读全文
0 0
- bzoj 2286 [Sdoi2011]消耗战 虚树
- BZOJ 2286 [Sdoi2011]消耗战 虚树
- BZOJ 2286: [Sdoi2011]消耗战
- bzoj 2286: [Sdoi2011]消耗战
- bzoj 2286: [Sdoi2011]消耗战
- BZOJ 2286: [Sdoi2011]消耗战
- 【BZOJ】2286: [Sdoi2011消耗战【虚树DP】
- bzoj 2286: [Sdoi2011消耗战 虚树+树形dp
- bzoj 2286 SDOI2011 消耗战 虚树dp
- 【BZOJ 2286】[Sdoi2011消耗战 虚树+dp
- bzoj 2286: [Sdoi2011]消耗战 虚树 DP
- 【BZOJ】2286 [Sdoi2011]消耗战 树形DP+虚树
- bzoj 2286: [Sdoi2011消耗战 (虚树+树形DP)
- [虚树+树形DP]BZOJ 2286—— [Sdoi2011]消耗战
- 【 bzoj 2286 】 : [Sdoi2011]消耗战 - 树形DP
- 2286: [Sdoi2011消耗战|树形DP|虚树
- 2286: [Sdoi2011消耗战
- 2286: [Sdoi2011消耗战
- Spring中<ref local=""/>与<ref bean=""/>区别
- 一分钟掌握数据库垂直拆分
- 获取位置
- 测试策略
- Ubuntu开机自动禁用无线网络的方法
- BZOJ 2286 [Sdoi2011]消耗战 虚树
- 【BZOJ3990】【SDOI2015】排序
- 安装
- SQL like 模糊查询
- 监听器的配置,绑定HttpSessionListener监听器的使用
- bash中的历史命令
- css权重
- CentOS MySQL配置
- 在单链表中删除倒数第K个节点 Python 版