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 ...
随机推荐
- 【5号课堂】scratch制作电子生日贺卡
贺卡在我国的使用由来已久,在古代,上层士大夫有用名帖互相问候的习俗 唐宋以后,贺卡的名称及功能有所进步,称为”门状“或“飞帖“,到了明清,又叫“红单“.“贺年帖“等等,听着名字就知功能越来越世俗化,文 ...
- 怎样解决多层this指向全局对象window的问题
如下所示, 得到的结果里面, 第二个this指向的是window这个全局对象而非f2, 原因就是多层this造成的指向不明引起的. var a = { f1: function(){ console. ...
- MQTTnet 3.0.5学习笔记
段时间在使用MQTTnet,都说这个东西比较好,可是翻了翻网上没有例子给参考一下. 今天算是找到了,给高手的帖子做个宣传吧. 原网址如下:https://blog.csdn.net/chenlu520 ...
- C#通过地址获取省市区(基于百度地图API)
最近公司有个需求,想通过地址获取对应的省市区,本来想直接通过对地址的截取,对于完整的地址还可以,不完整的就没法用了 所以本篇通过百度地图API来获取地址 第一步:申请ak密钥 登录百度地图开放平台,按 ...
- [书籍翻译] 《JavaScript并发编程》第四章 使用Generators实现惰性计算
本文是我翻译<JavaScript Concurrency>书籍的第四章 使用Generators实现惰性计算,该书主要以Promises.Generator.Web workers等技术 ...
- react请求接口数据是在componentDidMount 还是componentWillMount周期好
如果你要获取外部数据并加载到组件上,只能在组件"已经"挂载到真实的网页上才能作这事情,其它情况你是加载不到组件的.componentDidMount方法中的代码,是在组件已经完全挂 ...
- 升级xcode11&ios13的坑
Swift Packages 目前Pod跟SPM的兼容还没做好,配置好SPM后,Pod不能进行正常更新,先配置好Pod再集成SPM则没有问题 Pod以后的更新可能会解决这个问题,也会有越来越多的库支持 ...
- js中拼接html代码时onclick参数问题
一.如果是int类型.可以直接传参 二.如果是字符串类型.需要加上引号 1.使用转义符号\转义引号: (\''+strings+'\') 2.使用" .比如: ("'+strin ...
- Linux下的库文件搜索路径
对于以压缩包发布的软件,在它的目录下通常都有一个配置脚本configure,它的作用确定编译参数(比如头文件位置.连接库位置等),然后生成Makefile以编译程序.可以进入该软件的目录,执行 ...
- js中的分页
分页是前端经常会用到的一个非常实用的一个知识点,今天闲来没事,做了一个小demo,虽然样子,比较丑,哈哈哈,但是这是分页的核心思想都在,希望能给某个小伙伴一些启发.可直接复制在编辑器中运行. < ...