Luogu2495[SDOI2011]消耗战
题目描述
在一场战争中,战场由\(n\)岛屿和\(n-1\)个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为\(1\)的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他\(k\)个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到\(1\)号岛屿上)。不过侦查部门还发现了这台机器只能够使用\(m\)次,所以我们只需要把每次任务完成即可。
输入格式:
第一行一个整数\(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\),表示资源丰富岛屿的编号。
输出格式:
输出有\(m\)行,分别代表每次任务的最小代价。
【数据规模和约定】
对于\(10\%\)的数据,\(2<=n<=10,1<=m<=5,1<=ki<=n-1\)
对于\(20\%\)的数据,\(2<=n<=100,1<=m<=100,1<=ki<=min(10,n-1)\)
对于\(40\%\)的数据,\(2<=n<=1000,m>=1,sigma(ki)<=500000,1<=ki<=min(15,n-1)\)
对于\(100\%\)的数据,\(2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1\)
题目中\(k\)的总数有\(500000\),显然虚树优化树形\(DP\).因为是第一次写虚树所以出了不少\(bug\),这里来总结一下怎么写虚树.
首先,你要能建立出树形\(DP\)的朴素模型
在此基础上,由于询问点数和有限,所以我们并不需要对每次询问都\(O(N)\)\(DP\)回答.这里我们进行一次\(DFS\)的预处理,只抽出有效信息的一颗浓缩的树.那么关键就在怎么把它抽出来了.
对这个题,我们可以记录一个根节点到每个节点的最窄部分.然后对询问点按照\(dfs\)序排序.排序过后,对每两个\(dfs\)序相邻节点求\(lca\)扔进要用的点里.(可以口胡得到:这样一定涵盖所有必要的\(LCA\))再按\(dfs\)序排一次序,然后就可以愉快地建树\(DP\)啦.
Code:
#include <bits/stdc++.h>
#define int long long
#define N 250010
using namespace std;
int n, m, k, u, v, w, cnt, val[N], head[N];
int ss[N << 1], sta[N << 1], deep[N], ff[N][22], done[N];
struct edge {
int nxt, to, w;
}e[N << 1];
void add_edge (int from, int to, int val) {
e[++cnt].nxt = head[from];
e[cnt].to = to;
e[cnt].w = val;
head[from] = cnt;
}
int dfn[N], low[N], _dfn = 0;
void pre (int u, int fa) {
dfn[u] = ++_dfn;
deep[u] = deep[fa] + 1;
ff[u][0] = fa;
for (int i = 1; (1 << i) <= deep[u]; ++i) {
ff[u][i] = ff[ff[u][i - 1]][i - 1];
}
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
val[v] = min (val[u], e[i].w);
pre (v, u);
// printf ("val[%lld] = min (%lld, %lld)\n", v, val[u], e[i].w);
}
}
low[u] = _dfn;
}
bool cmp (const int &lhs, const int &rhs) {
return dfn[lhs] < dfn[rhs];
}
int lca (int u, int v) {
// printf ("lca (%lld, %lld) = ", u, v);
if (deep[u] < deep[v]) swap (u, v);
for (int i = 20; i >= 0; --i) {
if (deep[ff[u][i]] >= deep[v]) {
u = ff[u][i];
}
}
if (u == v) return u;
for (int i = 20; i >= 0; --i) {
if (ff[u][i] != ff[v][i]) {
u = ff[u][i];
v = ff[v][i];
}
}
//printf ("%lld\n", ff[u][0]);
return ff[u][0];
}
int get_ans (int u, int fa) {
if (done [u]) return val[u];
int res = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
res += get_ans (v, u);
}
}
return min (res, val[u]);
}
signed main () {
//freopen ("2495.in", "r", stdin);
scanf ("%lld", &n);
for (int i = 1; i < n; ++i) {
scanf ("%lld %lld %lld", &u, &v, &w);
add_edge (u, v, w);
add_edge (v, u, w);
}
memset (val, 0x3f, sizeof (val));
pre (1, 0);
/*
for (int i = 1; i <= n; ++i) {
printf ("node = %lld, val = %lld, low = %lld, dfn = %lld\n", i, val[i], low[i], dfn[i]);
} */
memset (head, 0, sizeof (head));
scanf ("%lld", &m);
for (int i = 1; i <= m; ++i) {
// printf ("ask = %lld\n", i);
scanf ("%lld", &k);
for (int j = 1; j <= k; ++j) {
scanf ("%lld", &ss[j]);
done[ss[j]] = true;
}
sort (ss + 1, ss + 1 + k, cmp);
for (int j = k; j > 1; --j) {
ss[++k] = lca (ss[j], ss[j - 1]);
}
ss[++k] = 1;
sort (ss + 1, ss + 1 + k, cmp);
k = unique (ss + 1, ss + 1 + k) - ss - 1;
int top = 0; cnt = 0;
for (int j = 1; j <= k; ++j) {
while (top && low[sta[top]] < dfn[ss[j]]) --top;
add_edge (sta[top], ss[j], val[j]);
add_edge (ss[j], sta[top], val[j]);
sta[++top] = ss[j];
}
get_ans (1, 0);
//print_tree (1, 0);
printf ("%lld\n", get_ans (1, 0));
for (int j = 1; j <= k; ++j) {
//printf ("dp[%lld] = %lld\n", ss[j], dp[ss[j]]);
done[ss[j]] = false, head[ss[j]] = 0;
}
}
}
Luogu2495[SDOI2011]消耗战的更多相关文章
- Luogu-2495 [SDOI2011]消耗战
虚树第一题 对于每次询问的点建立一棵虚树,然后在树上DP,一个点的答案就是这个点的父边切断的代价与所有儿子切断的代价去最小值,当然如果这个节点是资源点则必须切父边 注意在虚树上一条边的代价应该是中间所 ...
- BZOJ2286/Luogu2495 [Sdoi2011]消耗战 (虚树)
// never forget open "Head.cpp", boy, never ! #include <iostream> #include <cstdi ...
- BZOJ 2286: [Sdoi2011]消耗战
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2082 Solved: 736[Submit][Status] ...
- bzoj 2286: [Sdoi2011]消耗战 虚树+树dp
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...
- bzoj千题计划254:bzoj2286: [Sdoi2011]消耗战
http://www.lydsy.com/JudgeOnline/problem.php?id=2286 虚树上树形DP #include<cmath> #include<cstdi ...
- 【LG2495】[SDOI2011]消耗战
[LG2495][SDOI2011]消耗战 题面 洛谷 题解 参考博客 题意 给你\(n\)个点的一棵树 \(m\)个询问,每个询问给出\(k\)个点 求将这\(k\)个点与\(1\)号点断掉的最小代 ...
- AC日记——[SDOI2011]消耗战 洛谷 P2495
[SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 ...
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 4261 Solved: 1552 [Submit][Sta ...
随机推荐
- Windows Server 2012 Hyper-V 快照
快照 Hyper-V 可提供擷取執行中虛擬機器快照的能力,因此可輕易地回復至前一狀態,對於測試環境相當有幫助. 快照的功用雖然很不錯,不過每次建立快照時都是會消耗相當的硬碟資源,尤其目前的快照點和上一 ...
- cookie中的小错误
今天在练习 cookie时意外的报了这个错. 这句话的意思是一个不识别的字符[32]出现在了cookie当中由于tomcat的版本比较高,所以在addCookie时是不能使用空格的 而在ASCII码中 ...
- Nginx 返回响应过滤响应内容
陶辉94课 过滤模块 从下到上顺序 ngx_http_proxy_module 模块 Syntax: proxy_ignore_headers field ...; Default: — Contex ...
- 【C/C++】实现数据结构广义表
1. 广义表的定义 每个元素可以为Atom,原子,也可以为线性表. 线性表的推广.线性表元素有唯一的前驱和后继,为线性表,而广义表是多层次的线性表 表头:第一个元素,可能是 ...
- BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...
- Python入门-编写抓取网站图片的爬虫-正则表达式
//生命太短 我用Python! //Python真是让一直用c++的村里孩子长知识了! 这个仅仅是一个测试,成功抓取了某网站1000多张图片. 下一步要做一个大新闻 大工程 #config = ut ...
- 轮询、长轮询、websock
引入 Web端即时通讯技术:即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的.但是在Web中,由于浏览器的限制, ...
- 洛谷P1550打井
打井 题目 该题是一个最小生成树的好题,但是比起一般的最小生成树来说他不仅仅有各个井相连,而且还要和地下水相连,所以地下水我们也可以看成一口井. 代码 #include <bits/stdc++ ...
- Codeforces543 B. Destroying Roads
传送门:>Here< 题意:给出一张无向图(边权为1),并给出两对起点和终点以及距离:s1,t1,l1; s2,t2,l2; 要求删除尽量多的边,使得dis(s1,t1)<=l1, ...
- 阿里云上,Ubuntu下配置Nginx,在tomcat中加了https协议就不可以了
问题 阿里云上,Ubuntu服务器,本来部署的是tomcat,并且使用了https 协议.后来为了静态资源分离集成了 nginx,nginx代理跳转到 tomcat.刚开始直接访问http 网址发现, ...