题意:给定树上k个关键点,每个点属于离他最近,然后编号最小的关键点。求每个关键点管辖多少点。

解:虚树 + DP。

虚树不解释。主要是DP。用二元组存虚树上每个点的归属和距离。这一部分是二次扫描与换根法。

然后把关键点改为虚树节点,统计每个虚树节点管辖多少个节点,用SIZ表示,初始时SIZ = siz,SIZ[RT] = n。

如果一条虚树边两端点的归属相同。那么SIZ[fa] -= siz[son]

否则树上倍增找到y是最靠上属于的son的,然后SIZ[fa] -= siz[y] SIZ[son] = siz[y]

 #include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring> typedef long long LL;
const int N = , INF = 0x3f3f3f3f; struct Edge {
int nex, v, len;
}edge[N * ], EDGE[N * ]; int tp, TP; struct Node {
int x, d;
Node(int X = , int D = ) {
x = X;
d = D;
}
}small[N]; int e[N], E[N], RT, siz[N], d[N], num, pos[N], pw[N], Time, imp[N], stk[N], top, now[N], imp2[N];
int ans[N], fr[N], SIZ[N], n, fa[N][], use[N]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} inline void ADD(int x, int y) {
// printf("ADD %d %d \n", x, y);
TP++;
EDGE[TP].v = y;
EDGE[TP].len = d[y] - d[x];
EDGE[TP].nex = E[x];
E[x] = TP;
return;
} inline bool cmp(const int &a, const int &b) {
return pos[a] < pos[b];
} void DFS_1(int x, int father) {
fa[x][] = father;
d[x] = d[father] + ;
siz[x] = ;
pos[x] = ++num;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == father) {
continue;
}
DFS_1(y, x);
siz[x] += siz[y];
}
return;
} inline int lca(int x, int y) {
if(d[x] > d[y]) {
std::swap(x, y);
}
int t = pw[n];
while(t >= && d[x] < d[y]) {
if(d[fa[y][t]] >= d[x]) {
y = fa[y][t];
}
t--;
}
if(x == y) {
return x;
}
t = pw[n];
while(t >= && fa[x][] != fa[y][]) {
if(fa[x][t] != fa[y][t]) {
x = fa[x][t];
y = fa[y][t];
}
t--;
}
return fa[x][];
} inline void clear(int x) {
if(use[x] != Time) {
use[x] = Time;
E[x] = ;
}
return;
} inline void build_t(int k) {
std::sort(imp + , imp + k + , cmp);
TP = top = ;
clear(imp[]);
stk[++top] = imp[];
for(int i = ; i <= k; i++) {
int x = imp[i], y = lca(stk[top], x);
clear(x); clear(y);
while(top > && pos[y] <= pos[stk[top - ]]) {
ADD(stk[top - ], stk[top]);
top--;
}
if(y != stk[top]) {
ADD(y, stk[top]);
stk[top] = y;
}
stk[++top] = x;
}
while(top > ) {
ADD(stk[top - ], stk[top]);
top--;
}
RT = stk[top];
return;
} void out_t(int x) {
printf("out x = %d \n", x);
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
// printf("EDGE %d y %d \n", i, y);
out_t(y);
}
return;
} void getSmall(int x) {
(now[x] == Time) ? small[x] = Node(x, ) : small[x] = Node(n + , INF);
// printf("getSmall x = %d small = %d \n", x, small[x].x);
SIZ[x] = siz[x];
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
getSmall(y);
if(small[x].d > small[y].d + EDGE[i].len) {
small[x] = small[y];
small[x].d += EDGE[i].len;
}
else if(small[x].d == small[y].d + EDGE[i].len) {
small[x].x = std::min(small[x].x, small[y].x);
}
}
return;
} void getEXsmall(int x, Node t) {
// printf("EX x = %d small = %d \n", x, small[x].x);
if(small[x].d > t.d || (small[x].d == t.d && small[x].x > t.x)) {
small[x] = t;
}
// printf("x = %d small = %d \n", x, small[x].x);
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
getEXsmall(y, Node(small[x].x, small[x].d + EDGE[i].len));
}
return;
} inline int getPos(int x, int f) {
int t = pw[d[x] - d[f]], y = x;
while(t >= ) {
int mid = fa[y][t];
if(d[x] - d[mid] + small[x].d < d[mid] - d[f] + small[f].d) {
y = mid;
}
else if(d[x] - d[mid] + small[x].d == d[mid] - d[f] + small[f].d && small[f].x > small[x].x) {
y = mid;
}
t--;
}
return y;
} void del(int x, int f) {
// printf("del x = %d small = %d %d \n", x, small[x].x, small[x].d);
if(f) {
if(small[x].x == small[f].x) {
SIZ[f] -= siz[x];
// printf("SIZ %d -= %d = %d \n", f, siz[x], SIZ[f]);
}
else {
int y = getPos(x, f);
SIZ[f] -= siz[y];
// printf("SIZ %d -= %d = %d \n", f, siz[y], SIZ[f]);
SIZ[x] = siz[y];
// printf("SIZ %d = siz %d %d \n", x, y, siz[y]);
}
}
for(int i = E[x]; i; i = EDGE[i].nex) {
int y = EDGE[i].v;
del(y, x);
}
ans[small[x].x] += SIZ[x];
return;
} inline void solve() {
int k;
scanf("%d", &k);
Time++;
for(int i = ; i <= k; i++) {
scanf("%d", &imp[i]);
now[imp[i]] = Time;
ans[imp[i]] = ;
}
memcpy(imp2 + , imp + , k * sizeof(int));
build_t(k); // out_t(RT);
// get Small
getSmall(RT); // get Size
getEXsmall(RT, Node(n + , INF));
//
SIZ[RT] = n;
del(RT, );
for(int i = ; i <= k; i++) {
printf("%d ", ans[imp2[i]]);
}
printf("\n");
return;
} int main() { // freopen("in.in", "r", stdin);
// freopen("a.out", "w", stdout); scanf("%d", &n);
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
DFS_1(, );
for(int i = ; i <= n; i++) {
pw[i] = pw[i >> ] + ;
}
for(int j = ; j <= pw[n]; j++) {
for(int i = ; i <= n; i++) {
fa[i][j] = fa[fa[i][j - ]][j - ];
}
}
int q;
scanf("%d", &q);
while(q--) {
solve();
}
return ;
}

AC代码

洛谷P3233 世界树的更多相关文章

  1. 洛谷P3233 世界树 [HNOI2014] 虚树

    正解:虚树 解题报告: 传送门! 首先看到这种就要想到虚树这个是毫无疑问的QwQ 建虚树什么的都可以循规蹈矩地做,不说辣,具体可以看下虚树学习笔记什么的看下板子 但是建好虚树之后怎么搞还是有点儿讲究, ...

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

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

  3. 洛谷P3233 [HNOI2014]世界树

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

  4. 洛谷 P3233 [HNOI2014]世界树(虚树+dp)

    题面 luogu 题解 数据范围已经告诉我们是虚树了,考虑如何在虚树上面\(dp\) 以下摘自hzwer博客: 构建虚树以后两遍dp处理出虚树上每个点最近的议事处 然后枚举虚树上每一条边,考虑其对两端 ...

  5. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  6. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  7. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  8. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  9. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

随机推荐

  1. bootmgr is conmpressed联想Z485

    昨天清理磁盘空间的时候,手贱把驱动器给压缩了.再开机的时候就遇到了bootmgr is conmpressed. 我把解决办法发布到百度经验上了 http://jingyan.baidu.com/ar ...

  2. vue 动态修改 css

    <div v-for="i in resultDate" v-if="i.ProjectId>='4'" @click=EveyTesttInfo( ...

  3. 第七周 linux如何装载和启动一个可执行文件

    潘恒 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验内容 1.预处理. ...

  4. 猫咪记单词Beta版使用说明

    猫咪记单词Beta版使用说明 一.项目背景 英语四级考试.六级考试.托福.雅思等英语方面的考试是现在大学生必须面对的问题.同时因为学生对手机的使用越来越频繁,而且仅仅通过书本背诵单词又比较无聊坚持的时 ...

  5. 结构化分析(SA)

    1.什么叫模型?我觉得它的关键字:抽象 重要特征 降低复杂度. 2.软件设计的方法 分类:面向功能~,面向对象的设计. 面向数据流的方法是在结构化分析中提到的. 哦~ 3.面向数据流的结构化分析 特点 ...

  6. JSTLView快速国际化(SpringMVC)

    JSTLView:快速国际化:只要导入了jstl的jar包,以前默认创建的InternalResouceView都会被使用jstlView替代:    国际化的新步骤:           1).写好 ...

  7. Odoo中连接mysql数据库

    how to integrate Odoo with MySQL - Stack Overflowhttps://stackoverflow.com/questions/31959919/how-to ...

  8. Nginx rewrite模块深入浅出详解

    rewrite模块(ngx_http_rewrite_module) nginx通过ngx_http_rewrite_module模块支持url重写.支持if条件判断,但不支持else.另外该模块需要 ...

  9. 解决因为本地代码和远程代码冲突,导致git pull无法拉取远程代码的问题

    一.问题 当本地代码和远程代码有冲突的时候,执行git pull操作的时候,会提示有冲突,然后直接终止本次pull,查了些资料没有找到强制pull的方式,但是可以使用如下方式解决. 二.解决思路 可以 ...

  10. children和childNodes 的区别

    1.childNodes 属性,标准的,它返回指定元素的子元素集合,包括html节点,所有属性,文本.可以通过nodeType来判断是哪种类型的节点,只有当nodeType==时才是元素节点,是属性节 ...