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]世界树的更多相关文章

  1. luogu P3233 [HNOI2014]世界树

    传送门 我是什么时候写的这题的qwq 首先,发现关键点的总数被限制了,很自然想到虚树,并且,对于一个关键点,他管理的点显然是一个联通块 然后把虚树先建出来,然后两次dfs,第一次是向祖先更新离每个点最 ...

  2. [BZOJ3572][Hnoi2014]世界树

    [BZOJ3572][Hnoi2014]世界树 试题描述 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条 ...

  3. BZOJ 3572: [Hnoi2014]世界树

    BZOJ 3572: [Hnoi2014]世界树 标签(空格分隔): OI-BZOJ OI-虚数 OI-树形dp OI-倍增 Time Limit: 20 Sec Memory Limit: 512 ...

  4. bzoj 3572: [Hnoi2014]世界树 虚树 && AC500

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 520  Solved: 300[Submit][Status] ...

  5. bzoj 3572 [Hnoi2014]世界树(虚树+DP)

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status] ...

  6. 【BZOJ3572】[Hnoi2014]世界树 虚树

    [BZOJ3572][Hnoi2014]世界树 Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森 ...

  7. bzoj3572[Hnoi2014] 世界树 虚树+dp+倍增

    [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1921  Solved: 1019[Submit][Status][Dis ...

  8. <虚树+树型DP> HNOI2014世界树

    <虚树+树型DP> HNOI2014世界树 #include <iostream> #include <cstdio> #include <cstring&g ...

  9. [题解] [HNOI2014] 世界树

    题面 [HNOI2014]世界树 题解 从数据范围很容易看出是个虚树DP(可惜看出来了也还是不会做) 虚树大家应该都会, 不会的话自己去搜吧, 我懒得讲了, 我们在这里只需要考虑如何DP即可 首先我们 ...

随机推荐

  1. angular复选框式js树形菜单(一)

    treeView.html <ul class="tree-view"> <li ng-repeat="item in treeData" n ...

  2. CodeForces - 687D: Dividing Kingdom II (二分图&带权并查集)

    Long time ago, there was a great kingdom and it was being ruled by The Great Arya and Pari The Great ...

  3. ASP.net之HttpModel

    HttpModule是向实现类提供模块初始化和处置事件.当一个HTTP请求到达HttpModule时,整个ASP.NET Framework系统还并没有对这个HTTP请求做任何处理,也就是说此时对于H ...

  4. plsql Developer----plsql软件总结(待续更新)

    如何查看数据库所有的表 打开pl/sql Developer连接上数据库了以后,在菜单 Tools 下面有个 Object browser 将其打勾(如果已经打勾了就不用管了),之后在IDE的左边有个 ...

  5. Web打印的处理 方案之普通报表打印

    做过许多 的Web项目,大多数在打印页面内容的时刻 ,采用的都是议决 Javascript调用系统内置的打印要领 执行 打印,也就是调用 PrintControl.ExecWB(?,?)实现直接打印和 ...

  6. ELK多种架构及优劣

    圈子里关于大数据.云计算相关文章和讨论是越来越多,愈演愈烈.行业内企业也争前恐后,群雄逐鹿.而在大数据时代的运维挑站问题也就日渐突出,任重而道远了.本文旨在针对复杂的大数据运维系统推荐一把利器,达到抛 ...

  7. 第9章 DOM对象,控制HTML元素

    学习地址:http://www.imooc.com/learn/10

  8. MongoDb学习网站

    http://www.runoob.com/mongodb/mongodb-window-install.html

  9. shell脚本中常用命令

    1           Shell中的特殊符号 1.1           $  美元符号.用来表示变量的值.如变量NAME的值为Mike,则使用$NAME就可以得到“Mike”这个值. 1.2    ...

  10. Oracle 常用语句SQL

    查询Oracle 用户下面的所有表,表注释,行数 select t.TABLE_NAME, s.comments,t.NUM_ROWS  from user_tables t, user_tab_co ...