[虚树dp] bzoj2286: Sdoi2011消耗战
来源:互联网 发布:java 数据同步 编辑:程序博客网 时间:2024/06/14 17:29
Sdoi2011消耗战
题意:
给一棵带权树,1为根,q次询问,每次询问给出k个特殊点,要求去掉一些边,代价是权值,让点1不能到达k里的任意一个,输出最小代价。
题解:
首先考虑单次询问,容易想到dp[x]表示让1不能到x子树里的特殊点的代价。
当x是特殊点的时候,显然有dp[x]= min(path[x]),表示x到根节点的最小的那条边,因为一定要去掉x。
当x不是的时候,dp[x]=min(path[x], sum(dp[son(x)])),表示要么去掉x,要么去掉x所有儿子的子树的特殊点。
答案就是dp[1]。
现在变成多次询问,但是总的特殊点不超过
看了几篇blog学了一下虚树,这篇的写法很不错。
照着思路写就行了,代码还是比较容易的。
#include<bits/stdc++.h>using namespace std;const int N = 3e5+5;typedef long long ll;typedef pair<int,ll> edg;const ll inf = ~0ull>>5;vector<edg>G[N];vector<int>qry, GG[N];ll cost[N];int dep[N], fa[N][25], in[N], cnt = 0;int st[N], top;bool vis[N];inline bool cmp(const int& a, const int& b){ return in[a] < in[b];}void dfs1(int rt, int f){ in[rt] = ++cnt; for(int i = 1; i < 25; ++i){ if(dep[rt] < (1<<i)) break; fa[rt][i] = fa[fa[rt][i-1]][i-1]; } for(int i = 0; i < G[rt].size(); ++i){ int v = G[rt][i].first; if(v == f) continue; cost[v] = min(cost[rt], G[rt][i].second); dep[v] = dep[rt]+1; fa[v][0] = rt; dfs1(v, rt); }}int lca(int a, int b){ if(dep[a] < dep[b]) swap(a, b); int delt = dep[a] - dep[b]; for(int i = 0; i < 25; ++i){ if(delt&(1<<i)) a = fa[a][i]; } for(int i = 24; i >= 0; --i){ if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; } if(a != b) return fa[a][0]; else return a;}void add(int a, int b){ if(a == b) return; GG[a].push_back(b);}ll dp[N];void solve(int rt){ dp[rt] = cost[rt]; if(!vis[rt]){ ll sum = 0; for(int i = 0; i < GG[rt].size(); ++i){ solve(GG[rt][i]); sum += dp[GG[rt][i]]; } dp[rt] = min(dp[rt], sum); }}int main(){ int n; scanf("%d", &n); for(int a, b, c, i = 1; i < n; ++i){ scanf("%d%d%d", &a, &b, &c); G[a].push_back(edg(b, c)); G[b].push_back(edg(a, c)); } cost[1] = inf; dfs1(1, 1); int q; scanf("%d", &q); while(q--){ qry.clear(); int k; scanf("%d", &k); for(int a, i = 0; i < k; ++i){ scanf("%d", &a); qry.push_back(a); vis[a] = 1; } sort(qry.begin(), qry.end(), cmp); int len = qry.size(); for(int i = 1; i < len; ++i){ qry.push_back(lca(qry[i], qry[i-1])); } qry.push_back(1); sort(qry.begin(), qry.end(), cmp); qry.erase(unique(qry.begin(), qry.end()), qry.end()); int top = 0; for(int i = 0; i < qry.size(); ++i){ while(top > 0 && lca(st[top], qry[i]) != st[top]) top--; if(top) add(st[top], qry[i]); st[++top] = qry[i]; } solve(1); for(int i = 0; i < qry.size(); ++i) GG[qry[i]].clear(), vis[qry[i]] = 0; printf("%lld\n", dp[1]); }}
0 0
- 【bzoj2286】【sdoi2011】【消耗战】【虚树+dp】
- 【bzoj2286】[Sdoi2011消耗战 虚树+dp
- [虚树dp] bzoj2286: Sdoi2011消耗战
- [虚树 + DP] BZOJ2286: [Sdoi2011]消耗战
- 虚树+树形dp bzoj2286【Sdoi2011】 消耗战
- [BZOJ2286][SDOI2011]消耗战(虚树+树形DP)
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
- 【虚树+树形DP】BZOJ2286(Sdoi2011)[消耗战]题解
- [BZOJ2286][Sdoi2011消耗战] 虚树
- BZOJ2286: [Sdoi2011]消耗战 虚树
- BZOJ2286: [Sdoi2011]消耗战(虚树)
- [BZOJ2286][Sdoi2011]消耗战(虚树+lca+树形dp)
- bzoj2286: [Sdoi2011]消耗战
- bzoj2286[Sdoi2011消耗战
- [BZOJ2286] [Sdoi2011]消耗战
- [BZOJ2286][SDOI2011]消耗战
- BZOJ2286: [Sdoi2011]消耗战
- bzoj2286: [Sdoi2011消耗战
- iOS常见问题(2)
- NYOJ 1063 生活的烦恼
- 流(2)
- React实战-如何构建React+Flux+Superagent的完整框架
- 定时任务处理
- [虚树dp] bzoj2286: Sdoi2011消耗战
- Playing Atari with Deep Reinforcement Learning
- 异常处理(001)_什么是java中的异常
- java基础学习总结——线程之使用Runnable接口创建线程的方法
- leetcode Basic Calculator II
- HTML(JSP)
- H264—帧,片,参数集,NALU等概念
- java 语法
- (7)OpenGL多视口变换函数:glViewport使用