虚树模板题~洛谷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. python字符串的格式化输出

    很多时候我们在打印输入内容时希望有简单格式而不是拼接 一般做法: name = input("name:").strip() age = input("age:" ...

  2. node.js常用的fs文件系统

    fs文件系统模块对于系统文件及目录进行一些读写操作. 模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync(). 异步的 ...

  3. Git 项目提交代码及一些常用命令

    在dev_ysg分支 : git add . //把项目添加到仓库 git commit -m "test" // 提交加注释 git push //推到dev_ysg分支上去 g ...

  4. Java 使用Apache POI读取和写入Excel表格

    1,引入所用的包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxm ...

  5. 自定义控件,继承自 ListView

    public class MyListView extends ListView { /** * 如果在xml中创建并设置了style,就会调用三个参数的. * * @param context * ...

  6. python并发编程之多进程、多线程、异步、协程、通信队列Queue和池Pool的实现和应用

    什么是多任务? 简单地说,就是操作系统可以同时运行多个任务.实现多任务有多种方式,线程.进程.协程. 并行和并发的区别? 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任 ...

  7. java简单界面实现

    import javax.swing.JFrame; import javax.swing.JPanel; public class DemoFrame extends JFrame{ public ...

  8. Python自动化运维——IP地址处理模块

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 模块:IPy 功能:辅助我们高效的完成IP的规划工作 安装: wget https://pypi.python.o ...

  9. Fiddler 发送post 请求失败

    今天服务端同事,让我发一个post 请求.然后呢,一直有问题.告诉我签名失败. 后来换了其他的在线模拟post,都是可以的. 后来找到原因了, post 请求,必须要有Content-Type 和 C ...

  10. Anytime项目开发记录2

    注册,登陆于密码找回.这是这次记录的主要内容. 首先,我们来看类图: 因为一直在改,所以与第二篇介绍项目框架时的图会有一些不一样. 代码都是非常简单的. 由于在注册和登陆这里,需要弹出一些对话框告诉用 ...