洛谷P3979 遥远的国度 树链剖分+分类讨论
题意:给出一棵树,这棵树每个点有权值,然后有3种操作。操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值。
解法:如果没有修改树根操作那么这题就是树链剖分的裸题。但是修改树根操作会使得题目变得复杂一些,这里直接说结论:我们先直接以1为根建树进行树链剖分,这样的话根固定了那么路径修改操作就照常,然后我们要考虑换根操作对查询的影响(这是重点)。
画图分析后可以发现,可以分为3种情况,①x==rt,询问的就是整棵树 ②x不在1到rt的路径上,对查询没有影响,查询照常 3 x在1到rt的路径上,这样会麻烦一些,仔细观察图发现其实查询就变成了查询除去(x的rt所在的子树)那么我们就可以先用倍增找到(x的rt所在的子树)这颗子树的根为 y=rt的dep[rt]-dep[x]-1级祖先。这样查询除去y的子树剩下的左右两个区间合并就是答案了。
这道题还是很不错的,做了能涨处理这样的换根问题的姿势。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF=1LL<<;
const int N=1e5+;
int n,m,T,rt,num=,f[N][];
LL v[N];
struct node{
int dep,fa,sz,heavy;
int toseg,top; LL val;
}tree[N]; //原本的树
int totree[N<<]; //线段树点i代表原树的点totree[i] /*-------------------------以下为线段树-----------------------------*/
LL Min[N<<],tag[N<<];
void pushdown(int rt) {
if (!tag[rt]) return;
Min[rt<<]=tag[rt<<]=tag[rt];
Min[rt<<|]=tag[rt<<|]=tag[rt];
tag[rt]=;
}
void pushup(int rt) {
Min[rt]=min(Min[rt<<],Min[rt<<|]);
} void build(int rt,int l,int r) {
if (l==r) {
Min[rt]=tree[totree[l]].val; tag[rt]=;
return;
}
int mid=l+r>>;
build(rt<<,l,mid);
build(rt<<|,mid+,r);
pushup(rt);
} void update(int rt,int l,int r,int ql,int qr,LL v) {
if (ql<=l && r<=qr) {
Min[rt]=tag[rt]=v;
return;
}
int mid=l+r>>;
pushdown(rt);
if (ql<=mid) update(rt<<,l,mid,ql,qr,v);
if (qr>mid) update(rt<<|,mid+,r,ql,qr,v);
pushup(rt);
} LL query(int rt,int l,int r,int ql,int qr) {
if (ql<=l && r<=qr) return Min[rt];
int mid=l+r>>; LL ret=INF;
pushdown(rt);
if (ql<=mid) ret=min(ret,query(rt<<,l,mid,ql,qr));
if (qr>mid) ret=min(ret,query(rt<<|,mid+,r,ql,qr));
return ret;
} /*--------------------------以下为树链剖分----------------------------*/
int cnt=,head[N<<],to[N<<],nxt[N<<];
void add_edge(int x,int y) {
nxt[++cnt]=head[x]; to[cnt]=y; head[x]=cnt;
} void dfs1(int x,int fa,int dep) { //点x的父亲为fa深度为dep
tree[x].dep=dep;
tree[x].fa=fa;
tree[x].sz=;
tree[x].val=v[x];
int maxson=-;
for (int i=head[x];i;i=nxt[i]) {
int y=to[i];
if (y==fa) continue;
f[y][]=x; //在dfs1的时候顺便求倍增数组
for (int j=;j<=T;j++)
f[y][j]=f[f[y][j-]][j-];
dfs1(y,x,dep+);
tree[x].sz+=tree[y].sz;
if (tree[y].sz>maxson) tree[x].heavy=y,maxson=tree[y].sz;
}
} void dfs2(int x,int top) { //点x所在树链的top
tree[x].toseg=++num;
tree[x].top=top;
totree[num]=x;
if (!tree[x].heavy) return; //叶子结点
dfs2(tree[x].heavy,top); //先剖分重儿子
for (int i=head[x];i;i=nxt[i]) { //再剖分轻儿子
int y=to[i];
if (y==tree[x].fa || y==tree[x].heavy) continue;
dfs2(y,y);
}
} void update2(int x,int y,LL z) { //修改x到y路径的值
while (tree[x].top!=tree[y].top) { //不在同一条链上
if (tree[tree[x].top].dep<tree[tree[y].top].dep) swap(x,y); //x为深度大的链
update(,,n,tree[tree[x].top].toseg,tree[x].toseg,z); //x向上跳的同时更新
x=tree[tree[x].top].fa; //深度大的向上跳
}
if (tree[x].dep>tree[y].dep) swap(x,y); //这里x和y在同一条链
update(,,n,tree[x].toseg,tree[y].toseg,z); //x和y这条链的更新
} int getfa(int x,int k) { //取得x的k级祖先
if (k<) return -;
for (int i=T;i>=;i--)
if (k>=(<<i)) x=f[x][i],k-=(<<i);
return x;
} int main()
{
cin>>n>>m;
T=(int)log2(n)+;
for (int i=;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
add_edge(x,y); add_edge(y,x);
}
for (int i=;i<=n;i++) scanf("%lld",&v[i]);
dfs1(,,);
dfs2(,);
build(,,n);
scanf("%d",&rt);
for (int i=;i<=m;i++) {
LL opt,x,y,z; scanf("%lld",&opt);
if (opt==) {
scanf("%d",&rt);
}
if (opt==) {
scanf("%lld%lld%lld",&x,&y,&z);
update2(x,y,z);
}
if (opt==) {
scanf("%lld",&x);
if (x==rt) printf("%lld\n",query(,,n,,n)); //x就是root
else if (x==getfa(rt,tree[rt].dep-tree[x].dep)) { //x在1到root的路径上
y=getfa(rt,tree[rt].dep-tree[x].dep-); //取得去掉部分的根(这要画图理解)
z=INF;
if (tree[y].toseg->=) z=min(z,query(,,n,,tree[y].toseg-));
if (tree[y].toseg+tree[y].sz<=n) z=min(z,query(,,n,tree[y].toseg+tree[y].sz,n));
printf("%lld\n",z);
} else { //其他情况,直接查询子树
printf("%lld\n",query(,,n,tree[x].toseg,tree[x].toseg+tree[x].sz-));
}
}
}
return ;
}
洛谷P3979 遥远的国度 树链剖分+分类讨论的更多相关文章
- 洛谷 P4114 Qtree1 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...
- [洛谷P3384] [模板] 树链剖分
题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...
- 洛谷.4114.Qtree1(树链剖分)
题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...
- 洛谷3384&bzoj1036树链剖分
值得注意的是: 一个点的子树是存在一起的...也就是说我们修改子树的时候只用... /********************************************************* ...
- BZOJ 3083 遥远的国度 树链剖分
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 797 Solved: 181[Submit][Status] Descrip ...
- BZOJ 3083 遥远的国度(树链剖分+LCA)
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
- 【bzoj3083】遥远的国度 树链剖分+线段树
题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...
- BZOJ 3083: 遥远的国度(树链剖分+DFS序)
可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...
- BZOJ 3083 遥远的国度 树链剖分+线段树
有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio&g ...
随机推荐
- elasticsearch 嵌套对象之嵌套类型
nested类型是一种特殊的对象object数据类型(specialised version of the object datatype ),允许对象数组彼此独立地进行索引和查询. 1. 对象数组如 ...
- for循环(foreach型)举例
- 分支结构case 语句语法
- 力扣——single number 2(只出现一次的数字 2) python实现
题目描述: 中文: 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? ...
- 【Java程序】tesseract_orc java上的一种实现方法
今天想着把以前做过的一个Android的文字检测识别应用好好的回顾一下,因为以前写java程序,目的就是能用就行,不会仔细看每一个部分代码,也不会记他们的用法,不回会去查API,借鉴别人的例程,用过就 ...
- 转帖 移动前端开发之viewport的深入理解
在移动设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的viewport了,只有明白了viewport的概念以及弄清楚了跟viewport有关的meta标签的使用,才能更好地让我们的网页适配或 ...
- Foobar 2000增加APE播放支持的方法
这里说明一下APE,它是一种常用的无损音乐的存储格式,通常会有将原始音乐光盘数字化后存储的APE文件搭配一个CUE文件使用.这个APE存储了音乐的原始数据,而CUE文件则是一个索引文件,用来标记音乐光 ...
- 异常:Error response from daemon: conflict: unable to delete 6fa48e047721 (cannot be forced) - image has dependent child images
在删除镜像之前要先用 docker rm 删掉依赖于这个镜像的所有容器(哪怕是已经停止的容器),否则无法删除该镜像. 停止容器 # docker stop $(docker ps -a | grep ...
- Kaggle数据集下载
Kaggle数据集下载步骤: 安装Kaggle库: 注册Kaggle账户: 找到数据集,接受rules: 在My Account>>API中,点击Create New API Token, ...
- vue-cli创建的项目中引入第三方库报错'caller', 'calle', and 'arguments' properties may not be...
本文链接:https://blog.csdn.net/Sophie_U/article/details/76223978 问题: 在vue的main.js中引入mui.min.js时,报错. 如上,单 ...