题面

luogu

题解

数据范围已经告诉我们是虚树了,考虑如何在虚树上面\(dp\)

以下摘自hzwer博客:

构建虚树以后两遍dp处理出虚树上每个点最近的议事处

然后枚举虚树上每一条边,考虑其对两端点的答案贡献

可以用倍增二分出分界点

如果a,b的分界点为mid,a,b路径上a的第一个儿子为x

则对a的贡献是size[x]-size[mid]

对b的贡献是size[mid]-size[b]

还要算上没被考虑的点

Code

// luogu-judger-enable-o2
#include<bits/stdc++.h> #define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
int n;
const int N = 300010;
struct node {
int to, next;
}g[N<<1];
int last[N], gl;
inline void add(int x, int y) {
g[++gl] = (node) {y, last[x]};
last[x] = gl;
return ;
}
int dfn[N], cnt, siz[N], dep[N], anc[N][21], rem[N], bel[N];
void init(int u, int fa) {
dfn[u] = ++cnt; siz[u] = 1;
anc[u][0] = fa;
for (int i = 1; i <= 20; i++)
anc[u][i] = anc[anc[u][i-1]][i-1];
for (int i = last[u]; i; i = g[i].next) {
int v = g[i].to;
if (v == fa) continue;
dep[v] = dep[u]+1;
init(v, u);
siz[u] += siz[v];
}
return ;
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 20; i >= 0; i--)
if (dep[x]-(1<<i) >= dep[y])
x = anc[x][i];
if (x == y) return x;
for (int i = 20; i >= 0; i--)
if (anc[x][i] != anc[y][i])
x = anc[x][i], y = anc[y][i];
return anc[x][0];
}
int dis(int x, int y) {
return dep[x]+dep[y]-2*dep[lca(x, y)];
}
int top, len, m, a[N], b[N], s[N], c[N], f[N];
bool cmp(int a, int b) {
return dfn[a] < dfn[b];
} inline void insert(int x) {
if (top == 1) {s[++top] = x; return ;}
int o = lca(x, s[top]);
while (top > 1 && dfn[s[top-1]] >= dfn[o]) add(s[top-1], s[top]), top--;
if (o != s[top]) add(o, s[top]), s[top] = o;
s[++top] = x;
return ;
} void dfs1(int x) {
c[++len] = x; rem[x] = siz[x];
for (int i = last[x]; i; i = g[i].next) {
dfs1(g[i].to);
if (!bel[g[i].to]) continue;
int t1 = dis(bel[g[i].to], x), t2 = dis(bel[x], x);
if ((t1 == t2 && bel[g[i].to] < bel[x]) || t1 < t2 || !bel[x])
bel[x] = bel[g[i].to];
}
return ;
}
void dfs2(int x) {
for (int i = last[x]; i; i = g[i].next) {
int t1 = dis(bel[x], g[i].to), t2 = dis(bel[g[i].to], g[i].to);
if ((t1 == t2 && bel[g[i].to] > bel[x]) || t1 < t2 || !bel[g[i].to])
bel[g[i].to] = bel[x];
dfs2(g[i].to);
}
return ;
} void solve(int a, int b) {
int x = b, mid = b;
for (int i = 20; i >= 0; i--)
if (dep[anc[x][i]] > dep[a])
x = anc[x][i];
rem[a] -= siz[x];
if (bel[a] == bel[b]) {
f[bel[a]] += siz[x]-siz[b];
return ;
}
for (int i = 20; i >= 0; i--) {
int nxt = anc[mid][i];
if (dep[nxt] <= dep[a]) continue;
int t1 = dis(bel[a], nxt), t2 = dis(bel[b], nxt);
if (t1 > t2 || (t1 == t2 && bel[b] < bel[a])) mid = nxt;
}
f[bel[a]] += siz[x]-siz[mid];
f[bel[b]] += siz[mid]-siz[b];
return ;
} void query() {
top = len = gl = 0;
read(m);
for (int i = 1; i <= m; i++) read(a[i]), b[i] = a[i];
for (int i = 1; i <= m; i++) bel[a[i]] = a[i];
sort(a+1, a+1+m, cmp);
if (bel[1] != 1) s[++top] = 1;
for (int i = 1; i <= m; i++) insert(a[i]);
for (int i = 1; i < top; i++) add(s[i], s[i+1]);
dfs1(1); dfs2(1);
for (int i = 1; i <= len; i++)
for (int j = last[c[i]]; j; j = g[j].next)
solve(c[i], g[j].to);
for (int i = 1; i <= len; i++) f[bel[c[i]]] += rem[c[i]];
for (int i = 1; i <= m; i++) write(f[b[i]]), putchar(' ');
putchar('\n');
for (int i = 1; i <= len; i++) f[c[i]] = bel[c[i]] = last[c[i]] = 0;
return ;
} int main() {
read(n);
for (int i = 1; i < n; i++) {
int x, y;
read(x); read(y);
add(x, y); add(y, x);
}
init(1, 0);
memset(last, 0, sizeof(last));
int q; read(q);
while (q--) query();
return 0;
}

洛谷 P3233 [HNOI2014]世界树(虚树+dp)的更多相关文章

  1. 洛谷3233 HNOI2014(虚树+dp)

    膜拜一发\(mts\_246,forever\_shi\) 这两位爷是真的无敌! 首先来看这个题,一看题目的数据范围和"关键点"字眼,我们就能得知这是一道虚树题 那就先一如既往的建 ...

  2. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

  3. ●洛谷P3233 [HNOI2014]世界树

    题链: https://www.luogu.org/problemnew/show/P3233题解: 虚树,dp,倍增. 首先对于每个询问,要把虚树建出来,这一步就从略了.这里着重分享一下如何求答案. ...

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

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

  5. BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

    传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$ ...

  6. 洛谷P3233 [HNOI2014]世界树

    虚树= = #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring&g ...

  7. bzoj 3572世界树 虚树+dp

    题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...

  8. 【BZOJ】3572: [Hnoi2014]世界树 虚树+倍增

    [题意]给定n个点的树,m次询问,每次给定ki个特殊点,一个点会被最近的特殊点控制,询问每个特殊点控制多少点.n,m,Σki<=300000. [算法]虚树+倍增 [题解]★参考:thy_asd ...

  9. BZOJ 3572: [Hnoi2014]世界树 虚树 树形dp

    https://www.lydsy.com/JudgeOnline/problem.php?id=3572 http://hzwer.com/6804.html 写的时候参考了hzwer的代码,不会写 ...

随机推荐

  1. java代理模式与装饰者模式

    静态代理和装饰者模式的区别: 先来看一下装饰者模式的定义:装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 总结一下采用装饰者模式是为了增强或拓展原对象的功能. ...

  2. Junit问题01 利用 @Autowired 注入失效问题

    1 利用 @Autowired 注入失效问题 1.1 问题描述 在使用Junit作为测试框架的单元测试中,直接了用@Autowired记性依赖注入时总是注入失败 1.2 问题原因 在测试类中没有设定上 ...

  3. 19-格子游戏(hdu2147博弈)

    http://acm.hdu.edu.cn/showproblem.php?pid=2147 kiki's game Time Limit: 5000/1000 MS (Java/Others)    ...

  4. win32多线程(三) 死锁

    任何时候当一段代码需要两个(或更多)资源时,都有潜在性的死锁. void SwapLists(List *list1, List *list2) { List *tmp_list; EnterCrit ...

  5. HTML5 Canvas核心技术图形动画与游戏开发 ((美)David Geary) 中文PDF扫描版​

    <html5 canvas核心技术:图形.动画与游戏开发>是html5 canvas领域的标杆之作,也是迄今为止该领域内容最为全面和深入的著作之一,是公认的权威经典.amazon五星级超级 ...

  6. C#分布式存储演练(提供项目下载)

    C#简单的演练了一下分布式的存储,学习fastdns的结构,Client向ProcessCenter请求Storage的服务,然后上传文件. 分布式服务就是多个服务器作为客户端互相[配合],要中心化就 ...

  7. ArcGIS 工作经历【IFeatureBuffer】【CAD转SHP】

    由于工作需要,需要基于ArcGIS进行二次开发,软件的开发过程当中有一个非常重要的功能,就是需要把CAD的数据转换为shp文件保存,方便后面的使用编辑,存储. 先说一下功能的前提,需要将CAD转换为s ...

  8. angular 双向绑定

    <input type="text" [(ngModel)]="name"> {{name}} import { Component, OnInit ...

  9. WinForm中的重绘 - 文本的重绘

    两种方式 TextRenderer.DrawText 注意:默认在每次绘制的文本左右有padding,即使参数中设置了TextFormatFlags.NoPadding也是一样,因此在分段绘制文本时( ...

  10. 以太坊系列之五: p2p的nat模块--以太坊源码学习

    p2p的nat模块 该模块相对比较简单,因为nat的真正实现并不在此模块,主要是使用了第三方的nat-upnp和nat-pmp来实现真正的穿透(端口映射). 对外公布的接口 ```go // An i ...