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 ...
随机推荐
- windows环境下 快速杀死占用端口的进程
保存为bat脚本,设置需要解除占用的端口 port,点击运行即可 @echo off setlocal enabledelayedexpansion set prot = 8022 for /f &q ...
- C++标准库里自带的数值类型和字符串互相转换函数
需要包含头文件 #include <string> 数值类型转成string类型: string to_string(int val); string to_string(unsigned ...
- windows下监控进程的脚本
相信大家都有这样的需求,某程序(进程)在运行的时候可能挂掉,需要去监控该程序,并在它挂掉的时候重启之,确保该程序能一直运行.比如土net就经常挂,需要监控程序去监控.Linux下面似乎有守护进程的概念 ...
- JS基础 sessionStorage
html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage. sessionStorage用于本地存储一个会话(session)中的数据,这些数据只 ...
- Java 之 泛型
一.泛型概述 集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成 Object 类型.当我们取出一个对象,并且进行相应的操作,这时必须采用类型转换. 先观察下面代码: publ ...
- hive 存储格式对比
Apache Hive支持Apache Hadoop中使用的几种熟悉的文件格式,如TextFile,RCFile,SequenceFile,AVRO,ORC和Parquet格式. Cloudera I ...
- 雨后清风U盘启动盘的五大用处及制作方法
如果有一个U盘可以帮助你安装系统,或者在你的电脑系统崩溃时帮助你修复系统,是不是很方便呢?雨后清风U盘启动盘就能帮你实现这样的效果.除此之外,雨后清风U盘启动盘还有另外一些用处.下面就来和大家分享一下 ...
- Linux高级网络设置——将多个网卡设置成一个网卡
Linux下可以设置网卡模式 模式0:负载均衡 模式1:主备模式,不提高网络带宽 模式3:多网卡同时发送相同的数据 准备实验环境: Redhat 6.4 企业版64位,最小化安装. 给虚拟机添加网卡 ...
- 补充:HTML标签和CSS
角标标签: 上角标:sup 下角标:sub <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...
- 【2017-12-12】Winform----Datagirdview使用
1.数据绑定 DataGirdView.DataSource = list集合 2.复选框 获取复选框选中状态 for (int i = 0; i < dataGridView1.RowCoun ...