Luogu 3233 [HNOI2014]世界树
BZOJ 3572
首先看出虚树,然后考虑如何$dp$。
我们先在处理出的虚树上$dp$一遍,处理出虚树上所有点距离最近的关键点(关键点一定在虚树上嘛)。
具体来说,先搜一遍处理出每一个点的父亲到它的可能产生贡献的答案,然后再搜一遍处理出所有儿子到它的可能产生贡献的答案。
接下来考虑一下如何处理出所有不在虚树上的点对答案的贡献,我们去枚举虚树上的每一条边,如果这条边的两边被同一个关键点管辖,那么直接累加答案就行了,否则一定可以在原来的树链上找到一个中间点$mid$使$mid$上方的点都受管辖父亲的点管辖,$mid$下方的点都被管辖深度大的点的点管辖。
这个过程可以用倍增实现。
然而嘴巴是一回事,实现是另一回事……我实现了好久没实现出来,最后对着 ljh2000 大神的代码研究了挺长时间才写出来了。
放个链接吧。 戳这里
由于我的偷懒直接用两倍的点导致常数写大了……在Luogu上需要一发$O2$。
时间复杂度$O(nlogn)$。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 3e5 + ;
const int Lg = ;
const int inf = << ; int n, qn, tot = , head[N], dfsc = , in[N], out[N];
int fa[N][Lg], dep[N], top, sta[N * ], a[N * ], id[N], ans[N];
int bel[N], g[N], siz[N];
bool vis[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} bool cmp(int x, int y) {
int dfx = x > ? in[x] : out[-x];
int dfy = y > ? in[y] : out[-y];
return dfx < dfy;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} inline int min(int x, int y) {
return x > y ? y : x;
} void dfs(int x, int fat, int depth) {
fa[x][] = fat, dep[x] = depth, siz[x] = ;
in[x] = ++dfsc;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
siz[x] += siz[y];
}
out[x] = ++dfsc;
} inline int getLca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][];
} inline int getDis(int x, int y) {
int z = getLca(x, y);
return dep[x] + dep[y] - * dep[z];
} void dfs1(int x, int fat) {
g[x] = siz[x];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs1(y, x); if(bel[y] == ) continue;
if(bel[x] == ) {
bel[x] = bel[y];
continue;
} int d1 = getDis(bel[x], x), d2 = getDis(bel[y], x);
if(d2 < d1 || (d2 == d1 && bel[y] < bel[x])) bel[x] = bel[y];
}
} void dfs2(int x, int fat) {
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue; if(bel[y] == ) bel[y] = bel[x];
else {
int d1 = getDis(bel[y], y), d2 = getDis(bel[x], y);
if(d2 < d1 || (d2 == d1 && (bel[x] < bel[y]))) bel[y] = bel[x];
} dfs2(y, x);
}
} inline void work(int fat, int x) {
int son = x, mid = x;
for(int i = ; i >= ; i--)
if(dep[son] - ( << i) > dep[fat])
son = fa[son][i]; g[fat] -= siz[son];
if(bel[fat] == bel[x]) ans[bel[fat]] += siz[son] - siz[x];
else {
for(int i = ; i >= ; i--) {
int y = fa[mid][i];
if(dep[y] <= dep[fat]) continue;
int d1 = getDis(y, bel[fat]), d2 = getDis(y, bel[x]);
if(d1 > d2 || (d1 == d2 && bel[x] < bel[fat])) mid = y;
} ans[bel[fat]] += siz[son] - siz[mid];
ans[bel[x]] += siz[mid] - siz[x];
}
} void solve() {
int K; read(K);
for(int i = ; i <= K; i++) {
read(a[i]);
if(!vis[a[i]]) {
vis[a[i]] = ;
id[i] = a[i];
bel[a[i]] = a[i];
}
} int cnt = K;
sort(a + , a + + K, cmp);
for(int i = ; i < cnt; i++) {
int now = getLca(a[i], a[i + ]);
if(!vis[now]) {
vis[now] = ;
a[++cnt] = now;
}
} for(int cur = cnt, i = ; i <= cur; i++)
a[++cnt] = -a[i];
if(!vis[]) a[++cnt] = , a[++cnt] = -; sort(a + , a + + cnt, cmp); /* for(int i = 1; i <= cnt; i++) printf("%d ", a[i]);
printf("\n"); */ top = ;
for(int i = ; i <= cnt; i++) {
if(a[i] > ) sta[++top] = a[i];
else {
int x = sta[top--], y = sta[top];
if(y) add(x, y), add(y, x);
}
} dfs1(, ), dfs2(, ); for(int i = ; i <= cnt; i++) {
if(a[i] > ) sta[++top] = a[i];
else {
int x = sta[top--], y = sta[top];
if(y) work(y, x);
}
} for(int i = ; i <= cnt; i++)
if(a[i] > ) ans[bel[a[i]]] += g[a[i]]; for(int i = ; i <= K; i++)
printf("%d ", ans[id[i]]);
printf("\n"); tot = ;
for(int i = ; i <= cnt; i++)
if(a[i] > ) {
ans[a[i]] = head[a[i]] = g[a[i]] = bel[a[i]] = ;
vis[a[i]] = ;
}
} int main() {
read(n);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, , ); tot = ; memset(head, , sizeof(head));
for(read(qn); qn--; ) solve(); return ;
}
Luogu 3233 [HNOI2014]世界树的更多相关文章
- luogu P3233 [HNOI2014]世界树
传送门 我是什么时候写的这题的qwq 首先,发现关键点的总数被限制了,很自然想到虚树,并且,对于一个关键点,他管理的点显然是一个联通块 然后把虚树先建出来,然后两次dfs,第一次是向祖先更新离每个点最 ...
- [BZOJ3572][Hnoi2014]世界树
[BZOJ3572][Hnoi2014]世界树 试题描述 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条 ...
- BZOJ 3572: [Hnoi2014]世界树
BZOJ 3572: [Hnoi2014]世界树 标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增 Time Limit: 20 Sec Memory Limit: 512 ...
- bzoj 3572: [Hnoi2014]世界树 虚树 && AC500
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 520 Solved: 300[Submit][Status] ...
- bzoj 3572 [Hnoi2014]世界树(虚树+DP)
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 645 Solved: 362[Submit][Status] ...
- 【BZOJ3572】[Hnoi2014]世界树 虚树
[BZOJ3572][Hnoi2014]世界树 Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森 ...
- bzoj3572[Hnoi2014] 世界树 虚树+dp+倍增
[Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1921 Solved: 1019[Submit][Status][Dis ...
- <虚树+树型DP> HNOI2014世界树
<虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...
- [题解] [HNOI2014] 世界树
题面 [HNOI2014]世界树 题解 从数据范围很容易看出是个虚树DP(可惜看出来了也还是不会做) 虚树大家应该都会, 不会的话自己去搜吧, 我懒得讲了, 我们在这里只需要考虑如何DP即可 首先我们 ...
随机推荐
- angular复选框式js树形菜单(二)
删除(过滤)树形结构某一个子节点: function filterTreeData(treeData){ angular.forEach(treeData,function(item){ if (it ...
- xml获取指定节点的路径
引用自http://www.w3school.com.cn/xpath/xpath_syntax.asp XPath 语法 Previous Page Next Page XPath 使用路径表达式来 ...
- HDU2065"红色病毒"问题【指数型母函数】
Problem Description 医学界发现的新病毒因其蔓延速度和Internet上传播的"红色病毒"不相上下,被称为"红色病毒",经研究发现,该病毒及其 ...
- java-10异常处理动手动脑
1.请阅读并运行AboutException.java示例,然后通过后面的几页PPT了解Java中实现异常处理的基础知识. import javax.swing.*; class AboutExcep ...
- GO语言heap剖析及利用heap实现优先级队列
GO语言heap剖析 本节内容 heap使用 heap提供的方法 heap源码剖析 利用heap实现优先级队列 1. heap使用 在go语言的标准库container中,实现了三中数据类型:heap ...
- 基于JQ的多选/全选/反选及获取选中的值
<!-- author:青芒 --> <!DOCTYPE html> <html lang="en"> <head> <met ...
- oracle获得当前时间,精确到毫秒并指定精确位数
oracle获得当前时间的,精确到毫秒 可以指定精确豪秒的位数 select to_char(systimestamp, 'yyyymmdd hh24:mi:ss.ff ') from dual; ...
- python3 之初学者常犯的5个错误
1. Creating a copy of dictionary or lists. Whenever you need to make a copy of a dictionary or list, ...
- PHPExcel如何把该列的值设置为文本无科学计数?
$obj_sheet->setCellValueExplicit($cells[$_counter].$i, (isset($val[$_value_key]) ...
- commandLink/commandButton/ajax backing bean action/listener method not invoked (转)
Whenever an UICommand component fails to invoke the associated action method or an UIInputelement fa ...