BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,
每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接。
最少的边权和是多少。
(n<=250000,sigma(ki)<=500000)
考虑树形DP,我们令mn[i]表示i节点无法与1节点相连切除的最小权值。
显然有mn[i]=min(E(fa,i),mn[fa]).
大致就是i到1的简单路径上的最小边。
我们对于每个询问。把询问的点不妨称为关键点。
令dp[i]表示i节点不能与子树的关键点连接切掉的最小权值。
那么有,如果son[i]是关键点,则dp[i]+=E(i,son(i)).
如果son[i]不是关键点,则dp[i]+=min(dp[son(i)],E(i,son(i))).
考虑最坏每次只询问一个点,则复杂度为O(n*sigma(ki)).显然无法承受。
我们观察到sigma(ki)有限制,这启发了我们构造一颗新树,这棵树称为虚树。
我们把每个节点和每对节点的lca单独拉出来模仿原来的树的形态构造一颗虚树。
这样再在这颗新树上进行树形DP。
构造这棵树的核心思想是每次维护一条最右边的链。
首先把关键点按dfs序排序。
然后相邻的点取lca。
再单调栈维护一下最右边的链就ok啦。
- # include <stdio.h>
- # include <string.h>
- # include <stdlib.h>
- # include <iostream>
- # include <vector>
- # include <queue>
- # include <stack>
- # include <map>
- # include <math.h>
- # include <algorithm>
- using namespace std;
- # define lowbit(x) ((x)&(-x))
- # define pi acos(-1.0)
- # define MAXN
- # define eps 1e-
- # define MAXM
- # define MOD
- # define INF
- # define mem(a,b) memset(a,b,sizeof(a))
- # define FOR(i,a,n) for(int i=a; i<=n; ++i)
- # define FO(i,a,n) for(int i=a; i<n; ++i)
- # define bug puts("H");
- typedef long long LL;
- typedef unsigned long long ULL;
- int _MAX(int a, int b){return a>b?a:b;}
- int _MIN(int a, int b){return a>b?b:a;}
- int Scan() {
- int res=, flag=;
- char ch;
- if((ch=getchar())=='-') flag=;
- else if(ch>=''&&ch<='') res=ch-'';
- while((ch=getchar())>=''&&ch<='') res=res*+(ch-'');
- return flag?-res:res;
- }
- void Out(int a) {
- if(a<) {putchar('-'); a=-a;}
- if(a>=) Out(a/);
- putchar(a%+'');
- }
- struct Edge{int p, next, w;}edge[MAXN<<];
- int head[MAXN], cnt=, bin[], ind;
- int id[MAXN], dep[MAXN], fa[MAXN][], h[MAXN], st[MAXN], top;
- LL ans[MAXN], dp[MAXN];
- void add_edge(int u, int v, int w)
- {
- if (u==v) return ;
- edge[cnt].p=v; edge[cnt].next=head[u]; edge[cnt].w=w; head[u]=cnt++;
- }
- void bin_init(){bin[]=; FO(i,,) bin[i]=bin[i-]<<;}
- bool comp(int a, int b){return id[a]<id[b];}
- void dfs(int x, int fat)
- {
- id[x]=++ind;
- fa[x][]=fat;
- for (int i=; bin[i]<=dep[x]; ++i) fa[x][i]=fa[fa[x][i-]][i-];
- for (int i=head[x]; i; i=edge[i].next) {
- int v=edge[i].p;
- if (v==fat) continue;
- dep[v]=dep[x]+;
- ans[v]=min(ans[x],(LL)edge[i].w);
- dfs(v,x);
- }
- }
- int lca(int x, int y)
- {
- if (dep[x]<dep[y]) swap(x,y);
- int t=dep[x]-dep[y];
- for (int i=; bin[i]<=t; ++i) if (bin[i]&t) x=fa[x][i];
- for (int i=; i>=; --i) if (fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
- if (x==y) return x;
- else return fa[x][];
- }
- void dp_dfs(int x)
- {
- dp[x]=ans[x];
- LL temp=;
- for (int i=head[x]; i; i=edge[i].next) {
- int v=edge[i].p;
- dp_dfs(v);
- temp+=dp[v];
- }
- head[x]=;
- if (temp) dp[x]=min(dp[x],temp);
- }
- void sol()
- {
- int k, tot=;
- cnt=;
- scanf("%d",&k);
- FOR(i,,k) h[i]=Scan();
- sort(h+,h+k+,comp);
- h[++tot]=h[];
- FOR(i,,k) if (lca(h[tot],h[i])!=h[tot]) h[++tot]=h[i];
- st[++top]=;
- FOR(i,,tot) {
- int f=lca(h[i],st[top]);
- while (dep[f]<dep[st[top-]]) add_edge(st[top-],st[top],), top--;
- add_edge(f,st[top--],);
- if (f!=st[top]) st[++top]=f;
- st[++top]=h[i];
- }
- while (top>) add_edge(st[top-],st[top],), top--;
- dp_dfs();
- printf("%lld\n",dp[]);
- }
- int main()
- {
- int n, m, u, v, w;
- bin_init();
- n=Scan();
- FO(i,,n) u=Scan(), v=Scan(), w=Scan(), add_edge(u,v,w), add_edge(v,u,w);
- ans[]=(LL)<<; dfs(,);
- m=Scan();
- mem(head,);
- while (m--) sol();
- return ;
- }
BZOJ 2286 消耗战 (虚树+树形DP)的更多相关文章
- 【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. 一棵树上多次询问,且 ...
- BZOJ 2286 消耗战 - 虚树 + 树型dp
传送门 题目大意: 每次给出k个特殊点,回答将这些特殊点与根节点断开至少需要多少代价. 题目分析: 虚树入门 + 树型dp: 刚刚学习完虚树(好文),就来这道入门题签个到. 虚树就是将树中的一些关键点 ...
- 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]
消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1 ...
- 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: 5002 Sol ...
- BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca
BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...
- 【BZOJ-3572】世界树 虚树 + 树形DP
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1084 Solved: 611[Submit][Status ...
随机推荐
- 【再探backbone04】单页应用的基石-路由处理
前言 首先发一点牢骚,互联网公司变化就是快,我去一个团队往往就一年时间该团队就得解散,这不,公司居然把无线团队解散了,我只能说,我那个去!!! 我去年还到处让人来呢,一个兴兴向荣的团队说没就没了啊!我 ...
- 获取WIFI密码
在十年前,我还在上初中,班上只有极少数的富二代用得起手机:几年后诺基亚.摩托罗拉.三星手机开始盛行:近些年,安卓.苹果系统手机占据了基本整个市场,WIFI出变得越来越重要. Wifi万能钥匙数据库存储 ...
- SharePoint 2013 图文开发系列之可视化WebPart
有了WebPart开发的基础,再进行可视化WebPart开发,就容易多了.创建和开发过程,两者非常相似,下面,我们简单介绍下可视化WebPart的开发. 1.添加新项目,选择SharePoint 20 ...
- [转]给 C# 开发者的代码审查清单
这是为C#开发者准备的通用性代码审查清单,可以当做开发过程中的参考.这是为了确保在编码过程中,大部分通用编码指导原则都能注意到.对于新手和缺乏经验(0到3年工作经验)的开发者,参考这份清单编码会很帮助 ...
- Android开发学习——应用安装过程
首先一个android项目,然后编译和打包,将.java文件编译为.class,.class编译为.dex,将所有文件打包为一个apk,只编译代码,不编译资源. .apk里面的.arsc是资源的索引, ...
- 【代码笔记】iOS-圆角矩形
代码: - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. se ...
- IOS 杂笔-16 (-(void)scrollViewDidEndScrollingAnimation:方法使用注意)
今天在写项目的时候,遇到了一件令人抓狂的事情. 正如标题所示,被这个方法弄的团团转. -(void)scrollViewDidEndScrollingAnimation:是协议里的方法. 意味当动画结 ...
- JVM-漫游
Write once, Run Any where. Java Virtual Machine – JVM 的存在让 Java 开发变得简单,并且一次编写多处运行.其实,JVM 就是一个抽象的计算机, ...
- javascript - 封装原生js实现ajax
1 /* * ajax方法 */ var Ajax = function() { var that = this; //创建异步请求对象方法 that.createXHR = function() { ...
- Python基础1
本节内容2016-05-30 Python介绍 发展史 Python 2 0r 3? 安装 Hello word程序 变量 用户输入 模块初识 .pyc? 数据类型初识 数据运算 if...else语 ...