题面

洛谷

Bzoj

题解

很容易想到$O(nk)$的树形$dp$吧,设$f[i]$表示处理完这$i$颗子树的最小花费,同时再设一个$mi[i]$表示$i$到根节点$1$路径上的距离最小值。于是有:

$ f[i]=\sum min(f[son[i]], mi[son[i]]) $

这样就有$40$分了。

考虑优化:这里可以用虚树来优化,先把所有点按照$DFS$序进行排序,然后将相邻两个点的$LCA$以及$1$号点加入进$LCA$,然后虚树就构好了,考虑欧拉序的特殊性质,所以再还原出欧拉序,在上面做$dp$就好了。(xgzc告诉我可以再$dfs$一遍,但我不想写了,欧拉序多好啊)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::swap; using std::sort;
typedef long long ll; template<typename T>
void read(T &x) {
int flag = 1; x = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= flag;
} const int N = 2.5e5 + 10, Inf = 1e9 + 7;
int n, m, dfin[N], dfout[N], tim;
int cnt, from[N], to[N << 1], nxt[N << 1];
int siz[N], son[N], dep[N], top[N], fa[N];
int nt[N << 1], vis[N], s[N << 1], tt;
ll mi[N], f[N], dis[N << 1];
inline void addEdge(int u, int v, ll w) {
to[++cnt] = v, dis[cnt] = w, nxt[cnt] = from[u], from[u] = cnt;
}
inline bool cmp(const int &x, const int &y) {
int k1 = x > 0 ? dfin[x] : dfout[-x], k2 = y > 0 ? dfin[y] : dfout[-y];
return k1 < k2;
} void dfs(int u) {
siz[u] = 1, dfin[u] = ++tim, dep[u] = dep[fa[u]] + 1;
for(int i = from[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa[u]) continue;
mi[v] = min(mi[u], dis[i]);
fa[v] = u, dfs(v), siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
} dfout[u] = ++tim;
}
void dfs(int u, int t) {
top[u] = t; if(!son[u]) return ;
dfs(son[u], t);
for(int i = from[u]; i; i = nxt[i])
if(to[i] != son[u] && to[i] != fa[u]) dfs(to[i], to[i]);
}
int lca(int x, int y) {
int fx = top[x], fy = top[y];
while(fx != fy)
if(dep[fx] > dep[fy]) x = fa[fx], fx = top[x];
else y = fa[fy], fy = top[y];
return dep[x] < dep[y] ? x : y;
} int main () {
read(n);
for(int i = 1; i < n; ++i) {
int u, v; ll w; read(u), read(v), read(w);
addEdge(u, v, w), addEdge(v, u, w);
}
mi[1] = Inf, dfs(1), dfs(1, 1), read(m);
for(int i = 1; i <= m; ++i) {
int tot; read(tot);
for(int j = 1; j <= tot; ++j)
read(nt[j]), vis[nt[j]] = true, f[nt[j]] = mi[nt[j]];
sort(&nt[1], &nt[tot + 1], cmp);
for(int j = 1; j < tot; ++j) {
int cf = lca(nt[j], nt[j + 1]);
if(!vis[cf]) nt[++tot] = cf, vis[cf] = true;
}
int tmp = tot;
for(int j = 1; j <= tmp; ++j)
nt[++tot] = -nt[j];
if(!vis[1]) nt[++tot] = 1, nt[++tot] = -1;
sort(&nt[1], &nt[tot + 1], cmp);
for(int j = 1; j <= tot; ++j)
if(nt[j] > 0) s[++tt] = nt[j];
else {
int now = s[tt--];
if(now != 1) { int fat = s[tt]; f[fat] += min(f[now], mi[now]); }
else printf("%lld\n", f[1]);
f[now] = vis[now] = 0;
}
}
return 0;
}

Bzoj 2286 & Luogu P2495 消耗战(LCA+虚树+欧拉序)的更多相关文章

  1. P3379 【模板】最近公共祖先(LCA)(欧拉序+rmq)

    P3379 [模板]最近公共祖先(LCA) 用欧拉序$+rmq$维护的$lca$可以做到$O(nlogn)$预处理,$O(1)$查询 从这里剻个图 #include<iostream> # ...

  2. 【BZOJ 3772】精神污染 主席树+欧拉序

    这道题的内存…………………真·精神污染……….. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第 ...

  3. 【Luogu】P2495消耗战(虚树DP)

    题目链接 我虚树没很理解啊qwq 就是我们有比较少的询问点,然后我们把不需要考虑的点搞一搞扔掉,然后每次询问给那些询问点单独建一颗树,然后乱搞. ……好吧看来是完全没理解…… 链接大法qwq #inc ...

  4. 【BZOJ2286】消耗战(虚树,DFS序,树形DP)

    题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...

  5. bzoj 4026 dC Loves Number Theory 主席树+欧拉函数

    题目描述 dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源.给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代 ...

  6. lca 欧拉序+rmq(st) 欧拉序+rmq(线段树) 离线dfs 倍增

    https://www.luogu.org/problemnew/show/P3379 1.欧拉序+rmq(st) /* 在这里,对于一个数,选择最左边的 选择任意一个都可以,[left_index, ...

  7. BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca

    BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...

  8. 【BZOJ2286】消耗战(虚树,动态规划)

    [BZOJ2286]消耗战(虚树,动态规划) 题面 BZOJ Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总 ...

  9. [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)

    [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表) 题面 Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段 ...

随机推荐

  1. MSSQL DBOtherSQL

    --------------------------查询表中的数据------------------------------ --1.请查询出MyStudent表中的所有数据 --下面的语句表示查询 ...

  2. 如何免费上传4G以上大文件至百度云网盘

    百度云网盘的容量高达2048G,因而如今使用百度云网盘的用户也越来越多, 但是百度云中如果要上传超过4G的大文件,必须要升级VIP才行,但这需要收费.那么,超过4G以上的大文件我们该怎样上传到百度云呢 ...

  3. bzoj 2809 左偏树\平衡树启发式合并

    首先我们对于一颗树,要选取最多的节点使得代价和不超过m,那么我们可以对于每一个节点维护一个平衡树,平衡树维护代价以及代价的和,那么我们可以在logn的时间内求出这个子树最多选取的节点数,然后对于一个节 ...

  4. python作业三级菜单day1(第一周)

    一.作业需求: 1. 运行程序输出第一级菜单 2. 选择一级菜单某项,输出二级菜单,同理输出三级菜单 3. 菜单数据保存在文件中 4. 让用户选择是否要退出 5. 有返回上一级菜单的功能 二三级菜单文 ...

  5. js中的indexOf

    1.概述 indexOf大小写敏感,其中的O要大写 2.对于字符串而言 indexOf返回字符串第一次出现的位置,若没有出现返回-1 var str = "hello world" ...

  6. 盲注脚本2.基于bool

    盲注脚本2.基于bool #!/usr/bin/env python #encoding:utf-8 #by i3ekr #using # python sqlinject.py -D "数 ...

  7. Reactor与Proactor区别

    如网络编程中accept之后等待数据到达,并且读取数据为例: Reactor: 基于同步IO 1. 线程等待读取socket数据,将socketfd添加到事件分派器中,如添加到epoll: 2. 事件 ...

  8. C基础 mariadb处理简单案例

    引言 MariaDB 是一款灰常不错开源数据库. 这里直接用它来解决业务问题. 业务需求: 现在数据库中表示按照天分表的. 突然我们需要按照月来处理数据. 例如输入一个玩家id, 查找这个玩家这个月内 ...

  9. Python数据处理实战

    一.运行环境 1.python版本 2.7.13 博客代码均是这个版本2.系统环境:win7 64位系统 二.需求 对杂乱文本数据进行处理 部分数据截图如下,第一个字段是原字段,后面3个是清洗出的字段 ...

  10. 【VI Script】你不知道的脚本编程

    前言 近期,小黑在写程序的时候,经常会遇到一些重复性的工作.尤其是在写到QMH(Queued Message Handler)程序时,经常需要创建UI界面上的一些控件引用,并且在程序中捆绑成簇使用. ...