P3979 遥远的国度 树剖
P3979 遥远的国度 树剖
需要想一下的树剖题,对于询问三需要处理换跟后的情况。我们以1为树根跑一遍剖分,对于换跟进行分类讨论,算出实际答案。讨论有三种情况:
(以1为树根的树上)
跟在询问节点的祖先上:因为不影响,所以直接求子树最小值
跟即询问节点:直接查全树
跟在询问节点子树中:画图容易得出,此时询问节点范围包含全树除了\(son\)的子树,其中\(son\)为跟向上跳达到询问节点的上一个节点。于是我们除去线段树区间\([idx[son], idx[son]+sz[son]-1]\)分左右区间讨论就好了。
#include <cstdio>
#include <algorithm>
#define MAXN 100010
#define ll long long
#define sl (x<<1)
#define sr (x<<1|1)
using namespace std;
int head[MAXN],vv[MAXN*2],nxt[MAXN*2],tot;
const int INF=0x3fffffff;
inline void add_edge(int u, int v){
vv[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
int nod_val[MAXN];
int mxs[MAXN],sz[MAXN],dep[MAXN];
int f[MAXN][20];
void dfs1(int u, int fa){
dep[u]=dep[fa]+1;
f[u][0]=fa;
for(int i=1;i<=17;++i)
f[u][i]=f[f[u][i-1]][i-1];
sz[u]=1;
int mxsz=-1;
for(int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(v==fa) continue;
dfs1(v, u);
sz[u]+=sz[v];
if(mxsz<sz[v]){
mxsz=sz[v];
mxs[u]=v;
}
}
}
int idx[MAXN],topf[MAXN],cnt,wnew[MAXN];
void dfs2(int u, int top){
idx[u]=++cnt;
topf[u]=top;
wnew[cnt]=nod_val[u];
if(mxs[u]==0) return;
dfs2(mxs[u], top);
for(int i=head[u];i;i=nxt[i]){
int v=vv[i];
if(v==f[u][0]||v==mxs[u]) continue;
dfs2(v, v);
}
}
struct nod{
int l, r;
int val,lazy;
} tre[MAXN*4];
void buildt(int x, int l, int r){
tre[x].l=l,tre[x].r=r,tre[x].lazy=0;
if(l==r){
tre[x].val=wnew[l];
return;
}
int mid=(l+r)>>1;
buildt(sl, l, mid);
buildt(sr, mid+1, r);
tre[x].val=min(tre[sl].val, tre[sr].val);
}
void push_down(int x){
if(tre[x].lazy==0) return;
tre[sl].lazy=tre[sl].val=tre[x].lazy;
tre[sr].lazy=tre[sr].val=tre[x].lazy;
tre[x].lazy=0;
}
void change(int x, int l, int r, int val){
if(l<=tre[x].l&&tre[x].r<=r){
tre[x].lazy=tre[x].val=val;
return;
}
push_down(x);
int mid=(tre[x].l+tre[x].r)>>1;
if(l<=mid) change(sl, l, r, val);
if(mid<r) change(sr, l, r, val);
tre[x].val=min(tre[sl].val, tre[sr].val);
}
int query(int x, int l, int r){
if(l<=tre[x].l&&tre[x].r<=r){
return tre[x].val;
}
push_down(x);
int mid=(tre[x].l+tre[x].r)>>1;
int ans=INF;
if(l<=mid) ans=min(query(sl, l, r), ans);
if(mid<r) ans=min(query(sr, l, r), ans);
return ans;
}
void tre_change(int a, int b, int val){
while(topf[a]!=topf[b]){
if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
change(1, idx[topf[a]], idx[a], val);
a=f[topf[a]][0];
}
if(dep[a]<dep[b]) swap(a,b);
change(1, idx[b], idx[a], val);
}
int tre_lca(int a, int b){
while(topf[a]!=topf[b]){
if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
a=f[topf[a]][0];
}
if(dep[a]<dep[b]) return a;
return b;
}
int tre_query(int a){
return query(1, idx[a], idx[a]+sz[a]-1);
}
int get_son(int a, int b){
for(int i=17;i>=0;--i)
if(dep[f[b][i]]>dep[a]) b=f[b][i];
return b;
}
int n,q,cap;
int main()
{
scanf("%d %d", &n, &q);
for(int i=1;i<n;++i){
int a,b;
scanf("%d %d", &a, &b);
add_edge(a, b);
add_edge(b, a);
}
for(int i=1;i<=n;++i) scanf("%d", &nod_val[i]);
scanf("%d", &cap);
dfs1(1, 1);
dfs2(1, 1);
buildt(1, 1, n);
while(q--){
int opt;
scanf("%d", &opt);
if(opt==1){
scanf("%d", &cap);
}else if(opt==2){
int l,r,v;
scanf("%d %d %d", &l, &r, &v);
tre_change(l, r, v);
}else if(opt==3){
int t;
scanf("%d", &t);
int lca=tre_lca(t, cap);
if(t==cap) printf("%d\n", query(1, 1, n));
else if(lca!=t) printf("%d\n", tre_query(t));
else{
int son=get_son(t, cap);
int ans=min(query(1, 1, idx[son]-1), query(1, idx[son]+sz[son], n)); // 除去中间那个区间,分左右区间求
printf("%d\n", ans);
}
}else puts("Erro!");
}
return 0;
}
P3979 遥远的国度 树剖的更多相关文章
- 洛谷P3979 遥远的国度 树链剖分+分类讨论
题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...
- BZOJ 3083: 遥远的国度 (树剖+线段树)
传送门 解题思路 前两个操作都比较基础.对于第三个操作分类讨论一下,首先如果当前根不是要操作点的子树,那么就无影响,直接查询操作点的子树即可.第二种是当前根是操作点的子树,那就找到当前根到操作点这条链 ...
- 【树链剖分换根】P3979 遥远的国度
Description zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcw ...
- BZOJ3083 遥远的国度 【树剖】
题目 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务 ...
- 【Luogu】P3979遥远的国度(树链剖分)
题目链接 不会换根从暑假开始就困扰我了……拖到现在…… 会了还是很激动的. 换根操作事实上不需要(也不能)改树剖本来的dfs序……只是在query上动动手脚…… 设全树的集合为G,以root为根,u在 ...
- BZOJ 3083 遥远的国度(树链剖分+LCA)
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
- 【luogu P3979 遥远的国度】 题解
题目链接:https://www.luogu.org/problemnew/show/P3979 除了换根操作都是裸的树剖 所以换根时考虑: 1.我查询的根等于换的根:无影响 2.我查询的根是换的根的 ...
- 【BZOJ3083/3306】遥远的国度/树 树链剖分+线段树
[BZOJ3083]遥远的国度 Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了 ...
- 【bzoj3083】遥远的国度 树链剖分+线段树
题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...
随机推荐
- ASP.NET Core分布式项目-1.IdentityServer4登录中心
源码下载 一.添加服务端的api 1.添加NUGet包 IdentityServer4 点击下载,重新生成 2.添加Startup配置 打开Startup文件 public class Startup ...
- linux重启php服务
- sql注入测试(4)--如何防止该类缺陷发生
检查用户输入的合法性,确信输入的内容只包含合法的数据,数据检查应当在客户端和服务器端都执行之所以要执行服务器端验证,是为了弥补客户端验证机制脆弱的安全性.在客户端,攻击者完全有可能获得网页的源代码,修 ...
- sql 批量插入
create PROCEDURE insertinto as begindeclare @id int;set @id=1;while @id<10begininsert into perso ...
- 用Altium Designer16 绘制STM32开发板PCB 笔记
第一部分 Altium designer 软件概括 一.安装:要安装英文版,只安装pcb design和importers/exporters 二.设置:dxp-preferences我们关心的是sy ...
- ajax检查用户名重复
1.获取ajax对象 new XMLHttpRequest(); IE6-8: new ActiveXOject("Microsoft.XMLHTTP"); 兼容判断:if(XML ...
- modelsim仿真xilinx ram输出均为0
现象 在vivado2018.3下生成了RAM IP,丢到modelsim中仿真发现doutb输出均为0.调整AB端口的时钟速率,发现低于5ns不行,输出为0.但5ns以上正常. 解决方法 比对了vi ...
- 如何让某些用户对Marketing Cloud的contact数据只能实施只读操作
打开maintain business role这个应用: 创建一个新的business role,然后添加下列这几个catalogs: SAP_CEC_BC_MKT_ADM_PC Marketing ...
- MYSQL8.0以上版本ROOT密码报错及修改
在登录数据库过程中,如果遇到忘记root密码时,该如何解决? 1.使用管理员权限打开命令提示符,在命令行中输入: net stop mysql 2.待mysql服务停止后,输入: mysqld -- ...
- You're currently running Fcitx with GUI 错误解决 Fcitx
在英文版ubuntu配置输入法时,点击 Configure Current Input Method 会报以下的错误: You’re currently running Fcitx with GUI, ...