BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
2286: [Sdoi2011]消耗战
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 4261 Solved: 1552
[Submit][Status][Discuss]
Description
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
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
32
22
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
我一定要吐槽一下,神™c <= 100000,假的吧= =
我INF开了10^9都不够和c比,调了一中午对别人代码从头对到尾就是找不出错= =
MMP
唉,还是自己弱,刚学虚树,对建树过程不太自信
先说说树形dp,我们设f[i]表示i节点封锁的最小开销【我们把每条向上的边直接看做该点的权值】
则f[i] = min(v[i],∑f[to])
我们知道封锁父亲效果一定不比封锁儿子差,那么每个点u的权值可以看做v[u] = min(v[u的祖先们])、
直接做肯定T,O(mn),题目甚至直接都没有m的上限,而k的上限提醒我们只处理每次涉及到的点
如何抽出一棵树中单独的一些点呢?这就是虚树了
虚树
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k != -1; k = ed[k].nxt)
#define PP(a,b) printf("link %d -> %d\n",a,b)
using namespace std;
const int maxn = 250005,maxm = 510005;
const LL INF = 100000000000000000ll;
inline int RD(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
return out * flag;
}
int n,m,K,h[maxn],ne = 0,fa[maxn][20],dfn[maxn],dep[maxn],cnt = 0;
int s[maxn],t[maxn];
LL mn[maxn],f[maxn];
struct EDGE{int to,nxt; LL w;}ed[maxm];
inline void build(int u,int v,int w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
}
inline void add(int u,int v){if (u != v) {ed[ne] = (EDGE){v,h[u],0}; h[u] = ne++;}}
void dfs(int u,int ff,int d){
fa[u][0] = ff; dfn[u] = ++cnt; dep[u] = ++d;
Redge(u) if (ed[k].to != ff){
mn[ed[k].to] = min(mn[u],ed[k].w);
dfs(ed[k].to,u,d);
}
}
void init(){REP(j,19) REP(i,n) fa[i][j] = fa[fa[i][j - 1]][j - 1];}
int lca(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
int d = dep[u] - dep[v];
for (int i = 0; (1 << i) <= d; i++)
if (d & (1 << i)) u = fa[u][i];
for (int i = 19; i >= 0; i--)
if (fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i];
if (u == v) return u;
return fa[u][0];
}
inline bool cmp(const int& a,const int& b){return dfn[a] < dfn[b];}
void rebuild(){
int top,tot = 0; s[top = 1] = 1; ne = 0;
sort(t + 1,t + 1 + K,cmp); t[++tot] = t[1];
for (int i = 2 ; i <= K; i++) if (lca(t[i],t[tot]) != t[tot]) t[++tot] = t[i];
for (int i = 1; i <= tot; i++){
int u = t[i],v = lca(u,s[top]);
while (true){
if (dep[v] >= dep[s[top - 1]]){
add(v,s[top--]); if (v != s[top]) s[++top] = v;
break;
}
add(s[top - 1],s[top]); top--;
}
if (s[top] != u) s[++top] = u;
}
while (--top) add(s[top],s[top + 1]);
}
void dp(int u){
f[u] = mn[u]; LL tmp = 0;
Redge(u) dp(ed[k].to),tmp += f[ed[k].to];
h[u] = -1;
if (tmp == 0) f[u] = mn[u];
else if (tmp <= f[u]) f[u] = tmp;
}
void solve(){
K = RD(); REP(i,K) t[i] = RD();
rebuild(); dp(1);
printf("%lld\n",f[1]);
}
int main(){
memset(h,-1,sizeof(h));
n = RD(); int a,b,w;
for (int i = 1; i < n; i++) a = RD(),b = RD(),w = RD(),build(a,b,w);
mn[1] = INF; dfs(1,0,0); init();
REP(i,n) h[i] = -1;
m = RD(); while (m--) solve();
return 0;
}
BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】的更多相关文章
- BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5246 Solved: 1978[Submit][Status][Discuss] Descript ...
- 【BZOJ-2286】消耗战 虚树 + 树形DP
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2120 Solved: 752[Submit][Status] ...
- BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)
题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...
- BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序
https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...
- 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]
消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1 ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- [SDOI2011]消耗战(虚树+树形动规)
虚树dp 虚树的主要思想: 不遍历没用的的节点以及没用的子树,从而使复杂度降低到\(\sum\limits k\)(k为询问的节点的总数). 所以怎么办: 只把询问节点和其LCA放入询问的数组中. 1 ...
- bzoj2286: [Sdoi2011]消耗战 虚树
在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个 ...
- luogu P2495 [SDOI2011]消耗战 |虚树+LCA+dp
题目描述 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知 ...
随机推荐
- 事物总线模式实例——EventBus实例详解
事件总线模式是一种广泛运用于安卓开发之中的一种软件架构模式,而事件总线模式在安卓开发中最广泛的应用莫过于AndroidStudio提供的EventBus,所以我就EventBus来谈谈对事件总线模式的 ...
- MySQL学习路线图
- 局域网访问不到linux下的tomcat
问题描述: CentOS安装完成Tomcat后,访问本地:http://localhost:8080/正确.但局域网内无法访问,而且服务器可ping通 经查原因为防火墙开启: [root@localh ...
- 一步一步学Linq to sql(四):查询句法
select 描述:查询顾客的公司名.地址信息 查询句法: var 构建匿名类型1 = from c in ctx.Customers select new { 公司名 = c.CompanyName ...
- Android stadio bug
好生气啊,android stadio 有bug.自己的代码,一直没有生效,原来是stadio 的问题.只是因为我打开了增强模式,后来,buildToolVersion 改了之后,android st ...
- 【Spring实战】----开篇(包含系列目录链接)
[Spring实战]----开篇(包含系列目录链接) 置顶2016年11月10日 11:12:56 阅读数:3617 终于还是要对Spring进行解剖,接下来Spring实战篇系列会以应用了Sprin ...
- Linux 文件与目录管理命令
处理目录的常用命令 常见的处理目录的命令: ls: 列出目录 cd:切换目录 pwd:显示目前的目录 mkdir:创建一个新的目录,语法:mkdir [-mp] 目录名称 -m :配置文件的权限 -p ...
- 一丶人生苦短,我用python【第一篇】
1 解释器 解释器(英语:Interpreter),又译为直译器,是一种电脑程序,能够把高级编程语言一行一行直接转译运行.解释器不会一次把整个程序转译出来,只像一位"中间人",每次 ...
- 寻找完全数(C++)
[问题描述] 输入一个大于 1 的正整数 n,请你将大于 1 和小于或等于 n 的所有完全数输出.所谓完全数就是因子(不算其本身)之和等于它本身的数.例如 1+2+4+7+14=28,所以 28 是完 ...
- Ubuntu 常见错误及解决方法——长期不定时更新
1. 修复 /etc/sudoers 文件损坏导致不能使用 sudo 命令 这是之前错误地编辑了 /etc/sudoers 这个文件导致的,因此撤销编辑即可,但由于已经不能使用 sudo 命令,因此不 ...