洛谷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分 数组大小一定要开够 ...
随机推荐
- 利用 John the Ripper 破解用户登录密码
一.什么是 John the Ripper ? 看到这个标题,想必大家都很好奇,John the Ripper 是个什么东西呢?如果直译其名字的话就是: John 的撕裂者(工具). 相比大家都会觉得 ...
- PHP 设置调试工具XDebug PHPStorm IDE
先下载PHP扩展Xdebug https://xdebug.org, 可以复制自己的phpinfo粘贴到https://xdebug.org/wizard.php中, 会生成需要下载的版本, php. ...
- centos7.4下Jira6环境部署及破解操作记录(完整版)
废话不多说,以下记录了Centos7针对Jira6的安装,汉化,破解的操作过程,作为运维笔记留存. 0) 基础环境 192.168.10.212 Centos7.4 mysql 5.6 jdk 1.8 ...
- Keepalived基础知识-运维小结
keepalived介绍keepalived观察其名可知,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,它集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防 ...
- 详解centos7配置本地yum源的方法
近在使用虚拟机时遇到一些麻烦,因为公司内部有网络管理,所以vm连接不上外网,yum无法安装软件,怎么解决呢?–使用iso做本地yum源,可以解决大部份的包安装. vm安装的是centos7. 1.挂载 ...
- og标签对SEO的作用及用法
meta property=og标签对SEO的作用及用法,如果你仔细观察会发现本站点<head>代码中有一段:"property="og:image"这段代码 ...
- 12.9 Daily Scrum
在一些实现上,开发人员提出了意见,经过讨论后,我们决定取消“推荐餐厅”的功能,增加了“菜谱分类”的功能. 同时更新了相关人员的任务. Today's Task Tomorrow's Task 丁辛 ...
- Leetcode——66.加一
@author: ZZQ @software: PyCharm @file: leetcode66_加一.py @time: 2018/11/29 16:07 要求:给定一个由整数组成的非空数组所表示 ...
- [转帖]台积电近10万片晶圆报废,但7nm工艺将成2019营收主力
台积电近10万片晶圆报废,但7nm工艺将成2019营收主力 2019年02月18日 13:19 1784 次阅读 稿源:Expreview超能网 0 条评论 https://www.cnbeta.co ...
- delphi7调用数据库连接属性
背景:连接数据库用ADOQuery控件,但是程序一旦编译完成,如果想更改数据库连接设置还得重新修改ADOQuery的属性重新编译 如果可以在程序中可以随时设置ADOQuery的属性则会方便很多. 实现 ...