洛谷P3233 世界树
题意:给定树上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 世界树的更多相关文章
- 洛谷P3233 世界树 [HNOI2014] 虚树
正解:虚树 解题报告: 传送门! 首先看到这种就要想到虚树这个是毫无疑问的QwQ 建虚树什么的都可以循规蹈矩地做,不说辣,具体可以看下虚树学习笔记什么的看下板子 但是建好虚树之后怎么搞还是有点儿讲究, ...
- ●洛谷P3233 [HNOI2014]世界树
题链: https://www.luogu.org/problemnew/show/P3233题解: 虚树,dp,倍增. 首先对于每个询问,要把虚树建出来,这一步就从略了.这里着重分享一下如何求答案. ...
- 洛谷P3233 [HNOI2014]世界树
虚树= = #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring&g ...
- 洛谷 P3233 [HNOI2014]世界树(虚树+dp)
题面 luogu 题解 数据范围已经告诉我们是虚树了,考虑如何在虚树上面\(dp\) 以下摘自hzwer博客: 构建虚树以后两遍dp处理出虚树上每个点最近的议事处 然后枚举虚树上每一条边,考虑其对两端 ...
- 洛谷1640 bzoj1854游戏 匈牙利就是又短又快
bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...
- 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.
没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...
- 洛谷P1108 低价购买[DP | LIS方案数]
题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...
- 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP
题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...
- 洛谷P1710 地铁涨价
P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交 讨论 题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...
随机推荐
- BugkuCTF 计算器
前言 写了这么久的web题,算是把它基础部分都刷完了一遍,以下的几天将持续更新BugkuCTF WEB部分的题解,为了不影响阅读,所以每道题的题解都以单独一篇文章的形式发表,感谢大家一直以来的支持和理 ...
- html绝对路径,相对路径
.com/eat.php中引用.com/includes/headrt.php的话写includes/header.php .com/service/eat.php中引用.com/includes/h ...
- Centos下部署DRBD+NFS+Keepalived高可用环境记录
使用NFS服务器(比如图片业务),一台为主,一台为备.通常主到备的数据同步是通过rsync来做(可以结合inotify做实时同步).由于NFS服务是存在单点的,出于对业务在线率和数据安全的保障,可以采 ...
- 个人阅读作业2—《No Silver Bullet: Essence and Accidents of Software Engineering》读后感
在进行了一次结对编程.一次团队编程和一次个人编程项目后,读了<No Silver Bullet: Essence and Accidents of Software Engineering> ...
- Daily scrum 12.24
平安夜闲得想来一遍scrum,添加了之前ui组的数据库问题修复任务. 其实是之前忘记在任务中添加了.现在基本修复完成. Member Today’s task 林豪森 与学霸其他小组交流,处理整合问题 ...
- Linux课题实践三——程序破解
2.3 程序破解 20135318 刘浩晨 1. 掌握NOP.JNE.JE.JMP.CMP汇编指令的机器码 NOP:NOP指令即“空指令”.执行到NOP指令时,CPU什么也不做,仅仅当做一 ...
- 猫咪记单词Beta版使用说明
猫咪记单词Beta版使用说明 一.项目背景 英语四级考试.六级考试.托福.雅思等英语方面的考试是现在大学生必须面对的问题.同时因为学生对手机的使用越来越频繁,而且仅仅通过书本背诵单词又比较无聊坚持的时 ...
- java-过滤器、拦截器
1.基础知识 1.1面向对象编程(OOP).面向切面编程(AOP) 面向对象编程: 将需求功能划分为不同的.相对独立的和封装良好的类,使他们有属于自己的行为,依靠继承和多态等来定义彼此的关系. 面向切 ...
- 个人项目junit4测试
一.题目简介 用java编写一个程序,模拟ATM柜员机. 二.源码的github链接 www.github.com/liuxianchen/test 三.所设计的模块测试用例.测试结果截图 四 心得 ...
- JavaScript表单验证登录
在登录时,通常是将输入的信息原封不动的传送给后端的处理程序,然后处理之后返回结果,那么可能后端服务器的压力就很大,所以可以先在提交表单之前进行一些简单的检测,然后再发给后端,减小服务器的一部分压力: ...