【LG2495】[SDOI2011]消耗战

题面

洛谷

题解

参考博客

题意

给你\(n\)个点的一棵树

\(m\)个询问,每个询问给出\(k\)个点

求将这\(k\)个点与\(1\)号点断掉的最小代价

其中\(n\leq250000\) \(m\geq1\) \(\Sigma k_i\leq500000\)

暴力

考虑直接暴力\(dp\)

设\(dp[i]\)表示处理完\(i\)的子树的最小代价

则\(dp[i]\)\(=\)\(min\Sigma dp[son_i],mn[i]\)其中\(mn[i]\)代表根节点到\(i\)节点路径上的最小边权

这样的话复杂度\(O(nm)\)无法通过此题

但观察数据范围

发现利用\(\Sigma k_i\)比较小的特点切入

虚树

思想

就是只将树上有用的点提取出来进行\(dp\),重构一棵树

这里指询问点和它们的\(lca\)

构建

考虑如何建一颗虚树。

首先我们要先对整棵树dfs一遍,求出他们的dfs序,然后对每个节点以dfs序为关键字从小到大排序

同时维护一个栈,表示从根到栈顶元素这条链。

设当前要加入的节点为\(p\),栈顶元素为\(x=s[top],lca\)为它们的最近公共祖先

因为我们按照\(dfs\)序遍历,所以\(p\)不可能是\(lca\)

那么现在会有两种情况

1.\(lca\)为\(x\),直接将\(p\)入栈

2.\(x\),\(p\)位于不同的子树中,则此时\(x\)所在子树已经遍历完了,我们需对其进行构造

设栈顶元素为\(x\),第二个为\(y\)

若\(dfn[y]>dfn[lca]\),可连边\(y->x\),将\(x\)出栈。

若\(dfn[y]=dfn[lca]\),\(y\)=\(lca\),连边\(lca->x\),子树构建完毕。

若\(dfn[y]<dfn[lca]\),即\(lca\)在\(x\)、\(y\)之间,连边\(lca->x\),\(x\)出栈,再将\(lca\)入栈,子树构建完毕。

然后重复这个过程就可以了,不理解的话可以自己手玩一下。。。

复杂度

大约是\(O(\Sigma k_i的)\),可能会带一些小常数

然后这题的代码贴在这里了:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <vector>
using namespace std; inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
if (ch == '-') w = -1 , ch = getchar();
while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
return w * data;
}
typedef long long ll;
#define int ll
const int MAX_N = 250005;
const int MAX_LOG_N = 19;
struct Graph { int to, cost, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v, int w) { e[e_cnt] = (Graph){v, w, fir[u]}; fir[u] = e_cnt++; }
int N, M, s[MAX_N], _top, dfn[MAX_N], mn[MAX_N];
namespace cpp1 {
int dep[MAX_N], top[MAX_N], fa[MAX_N], size[MAX_N], son[MAX_N], tim;
void dfs1(int x) {
dep[x] = dep[fa[x]] + 1; size[x] = 1;
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa[x]) continue;
fa[v] = x; mn[v] = min(mn[x], e[i].cost);
dfs1(v);
size[x] += size[v];
if (size[v] > size[son[x]]) son[x] = v;
}
}
void dfs2(int x, int tp) {
top[x] = tp; dfn[x] = ++tim;
if (son[x]) dfs2(son[x], tp);
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to;
if (v == fa[x] || v == son[x]) continue;
dfs2(v, v);
}
}
int LCA(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return dep[x] > dep[y] ? y : x;
}
}
namespace cpp2 {
vector<int> G[MAX_N];
void add(int x, int y) { G[x].push_back(y); }
void ins(int x) {
if (_top == 1) { s[++_top] = x; return ; }
int lca = cpp1::LCA(x, s[_top]);
if (lca == s[_top]) return ;
while (_top > 1 && dfn[s[_top - 1]] >= dfn[lca]) add(s[_top - 1], s[_top]), _top--;
if (lca != s[_top]) add(lca, s[_top]), s[_top] = lca;
s[++_top] = x;
}
ll dfs(int x) {
if (G[x].size() == 0) return mn[x];
ll res = 0;
for (int i = 0; i < (int)G[x].size(); i++) res += dfs(G[x][i]);
G[x].clear();
return min(res, 1ll * mn[x]);
}
bool cmp(int a, int b) { return dfn[a] < dfn[b]; }
}
int a[MAX_N];
#undef int
int main () {
#define int ll
clearGraph();
N = gi();
for (int i = 1; i < N; i++) {
int u = gi(), v = gi(), w = gi();
Add_Edge(u, v, w);
Add_Edge(v, u, w);
}
fill(&mn[1], &mn[N + 1], LLONG_MAX / 2);
cpp1::dfs1(1); cpp1::dfs2(1, 1);
M = gi();
while (M--) {
int K = gi(); for (int i = 1; i <= K; i++) a[i] = gi();
sort(&a[1], &a[K + 1], cpp2::cmp);
s[_top = 1] = 1;
for (int i = 1; i <= K; i++) cpp2::ins(a[i]);
while (_top > 0) cpp2::add(s[_top - 1], s[_top]), _top--;
printf("%lld\n", cpp2::dfs(1));
}
return 0;
}

【LG2495】[SDOI2011]消耗战的更多相关文章

  1. BZOJ 2286: [Sdoi2011]消耗战

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2082  Solved: 736[Submit][Status] ...

  2. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  3. bzoj千题计划254:bzoj2286: [Sdoi2011]消耗战

    http://www.lydsy.com/JudgeOnline/problem.php?id=2286 虚树上树形DP #include<cmath> #include<cstdi ...

  4. AC日记——[SDOI2011]消耗战 洛谷 P2495

    [SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 ...

  5. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  6. BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 4261  Solved: 1552 [Submit][Sta ...

  7. 【BZOJ2286】[Sdoi2011]消耗战 虚树

    [BZOJ2286][Sdoi2011]消耗战 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的 ...

  8. 2286: [Sdoi2011]消耗战

    2286: [Sdoi2011]消耗战 链接 分析 虚树练习题. 构建虚树,在虚树上DP. 跟着gxb学虚-tree... 代码 #include <cstdio> #include &l ...

  9. BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6371  Solved: 2496[Submit][Statu ...

随机推荐

  1. [由于远程方关闭传输流,身份验证失败]一次处理支付接口bug记录

    因公司系统升级,出现突然有些银行卡不能支付的情况,最开始排查发现是第三方平台接口返回有问题: 返回如下: 从11月7日下午开始一直联系第三方,第三方开始排查,一直说是数据格式有问题. 修改格式以后问题 ...

  2. 郝斌 SqlServer2005 学习笔记

    1.0 什么是数据库 狭义:存储数据的仓库. 广义:可以对数据进行存储和管理的软件以及数据本身统称为数据库. 另外一种说法:数据库是由表.关系.操作组成. 2.0 为什么要学习数据库 几乎所有的应用软 ...

  3. HDU 6370 Werewolf 【并查集】

    任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6370 Werewolf Time Limit: 2000/1000 MS (Java/Others)   ...

  4. 【luogu P2491 [SDOI2011]消防】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2491 题外话: OI一共只有三种题--会的题,不会的题,二分题. 题解: step 1 求树的直径,把树的直 ...

  5. STM32平台SD卡的FatFS文件系统开发

    STM32平台SD卡的FatFS文件系统开发 系统平台: STM32系列的STM32F103ZE SPI方式与SD卡通信 SD上移植FatFS系统 1 FatFS文件系统 1.1 FatFS简介 Fa ...

  6. MySQL优化之Explain命令解读

    简述: explain为mysql提供语句的执行计划信息.可以应用在select.delete.insert.update和place语句上.explain的执行计划,只是作为语句执行过程的一个参考, ...

  7. iOS之webview加载网页、文件、html的方法

    UIWebView  是用来加载加载网页数据的一个框.UIWebView可以用来加载pdf.word.doc 等等文件 生成webview 有两种方法,1.通过storyboard 拖拽  2.通过a ...

  8. Android软件开发之SharedPreferences

    SharedPreferences 一种轻量级的数据保存方式 以键值对的方式存储 用于存储小批量的数据   使用方法: SharedPreferences sp= getSharedPreferenc ...

  9. Linux性能检查命令总结[转]

    一些常用的网络.IO.内存监控指令,Linux性能检查命令总结

  10. 学习 Linux_kernel_exploits 小记

    Linux_kernel_exploits+ 功能:自动生成UAF类型漏洞exp文件的工具,目前缺少文档介绍,可以参考test文件下的使用实例,但是源码中缺少dataflowanalyzer模块+ 相 ...