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即可 首先我们 ...
随机推荐
- HTTP协议 与 Requests库
HTTP协议 与 Requests库: 1 HTTP协议: 2 URL作为网络定位的标识: >>>> 用户通过url来定位资源 >>>> 然后通过 g ...
- 浅学soap--------3
//person.wsdl 标签 <?xml version="1.0" ?> <definitions name="person" targ ...
- C8051F340 USB0 寄存器访问
/*************************************************************************** * C8051F340 USB0 寄存器访问 ...
- Net Core 中使用 Consul 来存储配置
Net Core 中使用 Consul 来存储配置 https://www.cnblogs.com/Rwing/p/consul-configuration-aspnet-core.html 原文: ...
- Unity之将Texture保存成png
http://blog.csdn.net/bingheliefeng/article/details/51177505 using UnityEngine;using System.Collectio ...
- Python的交互模式和命令行模式
Pyhton的交互模式 在终端输入Python3命令就会进入家Python的交互模式,在交互模式下,输入一行代码,回车,就会执行这行代码. Python的命令行模式 在终端输入Python3 1.py ...
- asp.net 打印控件使用方法
打印的效果及控制性虽然不是很好,但是也能勉强使用,应付一般的打印还是 可以的了.代码如下所示: 代码 复制代码 代码如下: //调用PrintControl.ExecWB(?,?)实现直接打印和打印预 ...
- Maven里头的pom.xml配置详解
正常的pom配置文件如下所示: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http ...
- 锁存器 Latch v.s. 触发器 Flip-Flop
转载 http://guqian110.github.io/pages/2014/09/23/latch_versus_flip_flop.html 根据 Wiki: Flip-flop (elec ...
- Nagios 里面监控MySQL事务一直RUNNING没有结束的报警Shell脚本 (转)
序言: 业务报警订单提交异常,页面一直没有反应,排查后是事务没有提交或者回滚导致,想到如果及时监控事务的运行状态报警出来,那么就可以及时排查出问题所在,方便运营处理,所以自己就弄了一个s ...