Luogu 3979 遥远的国度
树剖已经是人尽皆知的sb题了吗……
很早以前就想填掉这坑了……
考虑到树链唯一,进行操作并不会对换根产生影响,那么我们的换根操作只要记下root在哪里就好了
询问的时候分类讨论:
1:root == x 直接返回全树最大值就好了
2:lca(root, x) != x,那就和x没什么关系了,只要返回原子树最大值就好了
3:lca(root, x) == x,说明x在root的上方,那么找到x的儿子中root的祖先y,除了y的子树就都是x的子树了
跳树链和找lca可以用倍增实现
总复杂度 O(nlog2n)
Code(写的很长……):
#include <cstdio>
using namespace std; const int N = 1e5 + ;
const int Lg = ;
const int inf = << ; int n, qn, a[N], tot = , head[N], root;
int dfsc = , id[N], siz[N], top[N];
int w[N], dep[N], fa[N][Lg], son[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;
} 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 int min(int x, int y) {
return x > y ? y : x;
} inline void chkMin(int &x, int y) {
if(y < x) x = y;
} inline void swap(int &x, int &y) {
int t = x;
x = y;
y = t;
} void dfs1(int x, int fat, int depth) {
siz[x] = , fa[x][] = fat, dep[x] = depth;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ]; int maxson = -;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs1(y, x, depth + );
siz[x] += siz[y];
if(siz[y] > maxson)
maxson = siz[y], son[x] = y;
}
} void dfs2(int x, int topf) {
w[id[x] = ++dfsc] = a[x], top[x] = topf;
if(!son[x]) return;
dfs2(son[x], topf);
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x][] || y == son[x]) continue;
dfs2(y, y);
}
} 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][];
} namespace SegT {
int s[N << ], tag[N << ]; #define lc p << 1
#define rc p << 1 | 1
#define mid ((l + r) >> 1) inline void up(int p) {
if(p) s[p] = min(s[lc], s[rc]);
} inline void down(int p) {
if(tag[p] == inf) return;
s[lc] = tag[lc] = s[rc] = tag[rc] = tag[p];
tag[p] = inf;
} void build(int p, int l, int r) {
tag[p] = inf;
if(l == r) {
s[p] = w[l];
return;
} build(lc, l, mid);
build(rc, mid + , r);
up(p);
} void modify(int p, int l, int r, int x, int y, int v) {
if(x <= l && y >= r) {
s[p] = tag[p] = v;
return;
} down(p);
if(x <= mid) modify(lc, l, mid, x, y, v);
if(y > mid) modify(rc, mid + , r, x, y, v);
up(p);
} int query(int p, int l, int r, int x, int y) {
if(x <= l && y >= r) return s[p];
down(p); int res = inf;
if(x <= mid) chkMin(res, query(lc, l, mid, x, y));
if(y > mid) chkMin(res, query(rc, mid + , r, x, y));
return res;
} } using namespace SegT; inline void mtree(int x, int y, int v) {
for(; top[x] != top[y]; ) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
modify(, , n, id[top[x]], id[x], v);
x = fa[top[x]][];
}
if(dep[x] > dep[y]) swap(x, y);
modify(, , n, id[x], id[y], v);
} inline int ask(int x) {
if(root == x) return s[];
int y = getLca(x, root);
if(y == x) {
int z = root;
for(int i = ; i >= ; i--)
if(dep[fa[z][i]] > dep[y])
z = fa[z][i];
return min(query(, , n, , id[z] - ), query(, , n, id[z] + siz[z], n));
} else return query(, , n, id[x], id[x] + siz[x] - );
} int main() {
read(n), read(qn);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs1(, , ); for(int i = ; i <= n; i++) read(a[i]);
dfs2(, );
build(, , n); read(root);
for(int op; qn--; ) {
read(op);
if(op == ) read(root);
if(op == ) {
int x, y, v;
read(x), read(y), read(v);
mtree(x, y, v);
}
if(op == ) {
int x;
read(x);
printf("%d\n", ask(x));
}
} return ;
}
Luogu 3979 遥远的国度的更多相关文章
- 【luogu P3979 遥远的国度】 题解
题目链接:https://www.luogu.org/problemnew/show/P3979 除了换根操作都是裸的树剖 所以换根时考虑: 1.我查询的根等于换的根:无影响 2.我查询的根是换的根的 ...
- [Luogu] 遥远的国度
https://www.luogu.org/problemnew/show/P3979 3种情况 x=root,很显然此时应当查询整棵树 lca(root,x)!=x ,此时直接查询x的子树即可,与换 ...
- 【Luogu】P3979遥远的国度(树链剖分)
题目链接 不会换根从暑假开始就困扰我了……拖到现在…… 会了还是很激动的. 换根操作事实上不需要(也不能)改树剖本来的dfs序……只是在query上动动手脚…… 设全树的集合为G,以root为根,u在 ...
- 洛谷 3979 BZOJ 3083 遥远的国度
[题解] 这道题除去根操作就是普通的树链剖分了.但是有换根操作怎么处理呢? 我们可以发现如果现在的根不在查询的点的子树里,那么对本次查询没有影响.如果现在的跟在查询的点x的子树里,那么答案将变为整棵树 ...
- [luogu3979][bzoj3083]遥远的国度
[luogu传送门] [bzoj传送门] 题目描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcww ...
- Luogu 1514 引水入城 (搜索,动态规划)
Luogu 1514 引水入城 (搜索,动态规划) Description 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N行M列的矩形,如上图 ...
- [luogu]P1514 引水入城[搜索][记忆化][DP]
[luogu]P1514 引水入城 引水入城 题目描述在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形 ,如下图所示,其中每个格 ...
- BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 1280 MBSubmit: 3127 Solved: 795[Submit][Status][Discu ...
- Luogu 魔法学院杯-第二弹(萌新的第一法blog)
虽然有点久远 还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题 沉迷游戏,伤感情 #include <queue> ...
随机推荐
- hdoj-1715-大菲波数(大斐波那契数列)
题目链接 import java.util.*; import java.math.*; public class Main{ public static void main(String[] arg ...
- 机械硬盘运行VMWare虚拟机太卡的解决办法
VMWare有个运行机制是:在硬盘生成内存的镜像文件以降低内存的使用量,而这个是可以配置的,如果你的内存足够大的话,就可以不使用这个内存镜像,从而提高运行效率:配置方法如下: 1.单个虚拟机的配置,修 ...
- Git和Github使用说明
1. 安装 官网地址:https://git-scm.com/downloads 我这里使用的是git version 2.19.1.windows.1,全程傻瓜式安装,点下一步即可,可以把命令模式和 ...
- RabbitMQ和Kafka可靠性
RabbitMQ和Kafka可靠性 https://www.cnblogs.com/haolujun/p/9641840.html 我们通过前文知道,RabbitMQ的队列分为master queue ...
- vmem驱动设备
vmem是内存多字符设备.包含vfs的open.read.write.ioctl.poll.fasync和release函数,device文件的读写. virtual_mem.c #include & ...
- 如何让 PADS Layout 识别到板框
如何让 PADS Layout 识别到板框 在很久很久以前 PADS Laout 还是 PowerPCB 的时候,铺铜是不认识板框的. 当有铺铜时必须复制一份板框再设置为铺铜才可以. 但到了 PADS ...
- Linux终端录屏与播放 script 命令
本文由Suzzz原创,发布于 http://www.cnblogs.com/Suzzz/p/4107700.html ,转载请保留此声明. 有时候可能想要记录在终端的所有操作包括输出等,将来作为视频播 ...
- mysql之 mysql 5.6不停机主从搭建(一主一从基于日志点复制)
环境说明:版本 version 5.6.25-log 主库ip: 10.219.24.25从库ip:10.219.24.22os 版本: centos 6.7已安装热备软件:xtrabackup 防火 ...
- 如何在IJ中使用Jaxb2通过xml定义生成对应的Java Entity类的文件
#0. 准备要转换的xml文件,在Project视界中,右击这个xml文件,在弹出的菜单上选择“Generate XSD schema from XML File...”, 按默认设置生成xsd文件. ...
- MSDN 学习网站
-MSDN中文网站http://msdn.microsoft.com/zh-cn/-MSDN Webcast 中文网络广播http://msdn.microsoft.com/zh-cn/dd79616 ...