虚树模板题~洛谷P2495

第一次写虚树,感觉好厉害呀~首先,这道题目的树形dp是非常显然的,要控制一个点&其子树所有点,要么在子树内部割边,要么直接切点该点与父亲的连边。所以dp[u]表示控制u点所需的最小代价。只是,注意到这样dp的复杂度是O(nm)的,十分不可接受,妥妥的TLE。不过,题目给出的条件中还有一条:Σki<=500000;说明虽然总共的点很多,但实际上每一次对答案可能有影响的点很少。

再一次想到之前dp的时候就应该发现的性质:一条链上,只需要在意链首的点(控制了链首也就控制了整棵子树),这样我们就可以想到:要是这一棵树很小,能够把对答案没有贡献的点尽量都去掉就可以以很小的复杂度完成每一轮询问的dp了。

怎样构建一棵虚树呢?首先,将整颗树dfs一遍,保存每一个点的dfs序号(记为dfn[i])。对于一次询问中的点:a[i]而言,将其按照dfs序从小到大排序,之后两两求出lca,排除那些在同一条链上的点(只保留链首)。之后,我们将1号点放入栈中。这个栈是一个单调栈,保证在任何时候栈中的元素都是一条链,且栈顶元素深度最大。我们记栈顶元素与当前点(之前保留下来的点)的lca为lca,之后的操作就十分显然了,我们要不断的将栈顶元素退栈(在退栈的同时连边构造虚树),直到退回lca与当前元素的那一条链上。注意如果lca不是最后的栈顶元素,lca也要进栈(在虚树上必须保留的一个点,记录了分叉的情况)。最后不要忘记将剩下的元素也用边连起来。

在虚树上面跑dp,一共也没几个点,自然就跑得很快啦。

#include <bits/stdc++.h>
using namespace std;
#define INF 99999999999LL
#define maxn 280000
#define ll long long
int timer, cnp = , n, m, head[maxn], dfn[maxn], dep[maxn], gra[maxn][];
int a[maxn], s[maxn], top, tot;
ll val[maxn], dp[maxn];
struct edge
{
int to, last;
ll co;
}E[maxn * ]; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} bool cmp(int a, int b)
{
return dfn[a] < dfn[b];
} void add(int x, int y, int co = )
{
if(x == y) return;
E[cnp].to = y, E[cnp].co = co;
E[cnp].last = head[x], head[x] = cnp ++;
} int LCA(int x, int y)
{
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; ~i; i --)
if(dep[gra[x][i]] >= dep[y]) x = gra[x][i];
for(int i = ; ~i; i --)
if(gra[x][i] != gra[y][i]) x = gra[x][i], y = gra[y][i];
return (x == y) ? x : gra[x][];
} void dfs(int u, int fa)
{
gra[u][] = fa, dfn[u] = ++ timer, dep[u] = dep[fa] + ;
for(int i = ; i <= ; i ++) gra[u][i] = gra[gra[u][i - ]][i - ];
for(int i = head[u]; i; i = E[i].last)
{
int v = E[i].to;
if(v == fa) continue;
val[v] = min(E[i].co, val[u]);
dfs(v, u);
}
} void DP(int u, int fa)
{
ll c = ; dp[u] = val[u];
for(int i = head[u]; i; i = E[i].last)
{
int v = E[i].to;
if(v == fa) continue;
DP(v, u);
c += dp[v];
}
head[u] = ;
if(c && c < val[u]) dp[u] = c;
} void solve()
{
int k = read();
for(int i = ; i <= k; i ++) a[i] = read();
sort(a + , a + + k, cmp);
cnp = , s[] = ; top = , tot = ;
for(int i = ; i <= k; i ++) if(LCA(a[i], a[tot]) != a[tot]) a[++ tot] = a[i];
for(int i = ; i <= tot; i ++)
{
int lca = LCA(s[top], a[i]);
while()
{
if(dep[lca] >= dep[s[top - ]])
{
add(lca, s[top]);
top --;
if(lca != s[top]) s[++ top] = lca;
break;
}
add(s[top - ], s[top]), top --;
}
s[++ top] = a[i];
}
while(top > ) add(s[top - ], s[top]), top --;
DP(, );
printf("%lld\n", dp[]);
} int main()
{
n = read();
val[] = INF;
for(int i = ; i <= n - ; i ++)
{
int x = read(), y = read(), z = read();
add(x, y, z), add(y, x, z);
}
dfs(, );
memset(head, , sizeof(head));
m = read();
for(int i = ; i <= m; i ++) solve();
return ;
}

【题解】SDOI2011消耗战的更多相关文章

  1. 【LG2495】[SDOI2011]消耗战

    [LG2495][SDOI2011]消耗战 题面 洛谷 题解 参考博客 题意 给你\(n\)个点的一棵树 \(m\)个询问,每个询问给出\(k\)个点 求将这\(k\)个点与\(1\)号点断掉的最小代 ...

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

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

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

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

  4. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

  5. BZOJ 2286: [Sdoi2011]消耗战

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. phpstudy启动时Apache启动不了

    打开cmd,输入:D:\phpStudy\PHPTutorial\Apache\bin\httpd.exe -t 回车,即显示错误信息 说是我们的有一个文件目录不存在或者不可读取, 出现这个一般有两种 ...

  2. 总结laravel假数据填充步骤

    定义好模型 xxx.php 定义好数据生成的规则 database/factories/XxxlFactory.php 写入生成数据的代码,控制好生成的数据数目,对生成后的数据做出修改 databas ...

  3. mac制作U盘启动器

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.所需工具及必要条件: 1. 首先需要一个大于16GB U盘. 2.电脑系统版本应该大于10.11.X(因为之前 ...

  4. Python自动化运维——系统性能信息模块

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 模块:psutil psutil是一个跨平台库,可以很轻松的为我们实现获取系统运行的进程和资源利用率等信息. 功能 ...

  5. 洛谷(P1006 传纸条)

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个mm行nn列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运 ...

  6. Hue 工具使用

    Hue 是一个 Web 接口的 Hadoop 分析数据工具,由 Cloudra 公司开源 官方网址 Github 地址 -> 安装方法 文档地址 一.Build 1.ubuntu安装所需环境(以 ...

  7. 安装和配置Sentry(收录)

    安装和配置Sentry 本文主要记录安装和配置Sentry的过程,关于Sentry的介绍,请参考 Apache Sentry架构介绍 . 1. 环境说明 系统环境: 操作系统:CentOs 6.6 H ...

  8. shell -- sed用法

    sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法sed命令行格式为:         sed ...

  9. 今天买了个pro,开始ios开发

    今天买了个mac pro 开始ios开发啦,爽!

  10. Qt BarChart实践

    按照帮助文档编写 运行截图 上代码 #include "widget.h" #include "ui_widget.h" Widget::Widget(QWid ...