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即可 首先我们 ...
随机推荐
- (转)关于Linux核心转储文件 core dump
所谓核心转储文件是内含进程终止时内存映像的一个文件.产生条件:特定的信号会引发进程创建一个核心转储文件并终止运行. 包括哪些特定信号,请参见http://man7.org/linux/man-page ...
- npm init node 通过指令创建一个package.json文件及npm安装package.json
描述包的文件是package.json文件. 一个这样的文件,里面的信息还是挺大的.我们可以放弃手动建立.为了练手我们有命令行来建一个这样的包; 完成name,varsion....license项的 ...
- UV有问题?
1.检查读取显示贴图的环境与制作贴图环境UV坐标系是否一致. 如:Directx左上角(0,0),右下角(1,1) unity 左下角(0,0),右上角(1,1) 两者互转需要垂直镜像.
- mysql之 mysql 5.6不停机主从搭建(一主一从基于日志点复制)
环境说明:版本 version 5.6.25-log 主库ip: 10.219.24.25从库ip:10.219.24.22os 版本: centos 6.7已安装热备软件:xtrabackup 防火 ...
- 洛谷【P1439】【模板】最长公共上升子序列
浅谈\(DP\):https://www.cnblogs.com/AKMer/p/10437525.html 题目传送门:https://www.luogu.org/problemnew/show/P ...
- 操作Oracle 一条龙
1 引用Oracle.DataAccess.dll 2 App.Config中配置连接字符串: Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TC ...
- HDOJ1016(标准dfs)
Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- Oracle 下ASM磁盘总结
Oracle 下ASM磁盘总结 文章转载: Oracle下创建ASM磁盘总结https://blog.csdn.net/okhymok/article/details/78791841?utm_sou ...
- 一段小程序理解getchar和putchar
#include "stdafx.h" #include <iostream> using namespace std; int main() { char c,d,e ...
- redis学习二 排序
文章转载自:http://www.cnblogs.com/redcreen/archive/2011/02/15/1955226.html redis支持对list,set和sorted set元素的 ...