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 ...
随机推荐
- 网络模式: host-only & NAT & 桥接
基本上,Host-only相当于虚拟机和宿主机通过交叉线相连:NAT,宿主机相当于虚拟机的路由器:桥接,相当于把宿主机和虚拟机同时接到交换机上,然后交换机接到外网. 连接性上说,可参考下表: 连接 宿 ...
- 为什么用JS取不到cookie的值?解决方法如下!
注意:cookie是基于域名来储存的.要放到测试服务器上或者本地localhost服务器上才会生效.cookie具有不同域名下储存不可共享的特性.单纯的本地一个html页面打开是无效的. 明明在浏览中 ...
- java 获取json字符串中key对应的值
用到了Gson的JsonParser maven项目引入 <dependency> <groupId>com.google.code.gson</groupId> ...
- Sqlserver查询每组数据中最大的一条数据
select * from ( SELECT ROW_NUMBER() over (PARTITION By name order by val) as rowId,tb_test.* FROM tb ...
- .NET Core 发布部署问题
运行环境 操作系统 开发工具 frameworks .Net Core SDK 版本 托管运行 本地 ...
- 微信小程序wx:key以及wx:key=" *this"详解:
今天写微信小程序无意中看到控制台给出了这样一行提示: 求解百度才知道,给大家分享一下: 1.wx:for定义 官方文档:在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲 ...
- 【原创】大叔经验分享(88)jenkins假死
jenkins安装启动后,使用systemctl来进行进程监控 # systemctl enable jenkins 但是还是经常发生jenkins进程挂了,不会自动重启,通过systemctl查看状 ...
- leetcode-8.atoi · string *
题面 原题挺长的,还是英文,就不抄了,
- C语言计算两个日期间隔天数
在网上看到了一个C语言计算日期间隔的方法,咋一看很高深,仔细看更高神,很巧妙. 先直接代码吧 #include <stdio.h> #include <stdlib.h> in ...
- java实战(一)-------jdk环境在windows安装及配置
1.jdk官方下载 http://www.oracle.com/technetwork/java/javase/downloads/index.html 点击下载windows的版本:jdk-13.0 ...