[luogu3979][bzoj3083]遥远的国度
题目描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
题目大意
三种操作:变根,路径修改,查询子树中点权最小。
题解
非常明显,是一道树链剖分的模板题。
之后跟上算法xio小讲堂的地址(应该是第4讲)。
对于树链剖分,个人的理解就是将一棵树通过重轻的性质,展开到一个一维数组上,然后再通过各种数据结构来优化,比如说是线段树,并且我们树上的各个条链上的节点,在一维上的点是连续的,这样保证修改查询的顺序的可行性。
一个常识:在树链剖分中展开的一维数组中,原树上的节点\(u\)的范围是\(idx[u]\)~\(idx[u]+sz[u]-1\),其中\(idx\)表示原来节点现在的编号,\(sz\)表示以\(u\)为根的子树的节点数。(为什么是这样我会在第4期的xio讲堂里讲解)
对于这一道题,除了一般的路径修改还有改变根节点的操作。
我们将这个根节点的操作简单化。
如果我们要求\(x\)节点为根的最小节点,整棵树的根节点是\(root\)。
如果\(x=root\),显而易见,我们访问节点的答案就是整棵树的最小值。
如果\(lca(x,root)!=x\),也就是x和root是在两个不同的链上,那么我们的答案也就是原来的\(x\)的子树的答案。
那么最后一种情况就是\(lca(x,root)=x\),那么也就是说\(x\)成为了当前我们根节点的祖先。
这个玩意比较麻烦,但是画一张图,自己仔细观察一下,可以发现:我们要求的答案就是在\(root\)所在\(u\)的子树这条链以外的的所有其他子树。
那么我们就需要通过在一维数组中展开的树上的性质,枚举\(u\)节点的所有子节点,如果有一个节点深度比\(root\),而且\(idx+sz-1\)≥root的编号,也就是说我们root就在\(v\)(当前访问\(u\)号节点)的子树内,那么我们就可以直接算答案了。
\(ps\).求这道题的\(lca\)可以是用倍增,其实差不多的。
ac代码
#include<bits/stdc++.h>
#define ms(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define N 1000005
using namespace std;
struct edge{
int to,nt;
}E[N<<1];
int cnt,n,m,tot,rt;
int H[N],sz[N],top[N],dep[N],fa[N],son[N],idx[N],val[N],a[N];
int read(){
int w=0,x=0;char ch=0;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return w?-x:x;
}
void addedge(int u,int v){
E[++cnt]=(edge){v,H[u]}; H[u]=cnt;
E[++cnt]=(edge){u,H[v]}; H[v]=cnt;
}
struct segment_tree{//线段树维护树链
#define lson (nod<<1)
#define rson (nod<<1|1)
#define mid (l+r>>1)
int tr[N<<2],lazy[N<<2];
void pushup(int nod){tr[nod]=min(tr[lson],tr[rson]);}//pushup操作
void pushdown(int nod){//下放懒标记
if(lazy[nod]==-1) return;
tr[lson]=tr[rson]=lazy[nod];
lazy[lson]=lazy[rson]=lazy[nod];
lazy[nod]=-1;
}
void build(int l,int r,int nod,int *a){
lazy[nod]=-1;
if(l==r){
tr[nod]=a[l];
return;
}
build(l,mid,lson,a);
build(mid+1,r,rson,a);
pushup(nod);
}
void update(int l,int r,int ql,int qr,int v,int nod){//区间修改
if(ql<=l&&r<=qr){
tr[nod]=v;
lazy[nod]=v;
return;
}
pushdown(nod);
if(ql<=mid) update(l,mid,ql,qr,v,lson);
if(qr>mid) update(mid+1,r,ql,qr,v,rson);
pushup(nod);
}
int query(int l,int r,int ql,int qr,int nod){//区间查询
if(ql>r||qr<l) return inf;
if(ql<=l&&r<=qr) return tr[nod];
pushdown(nod);
int res=inf;
res=min(res,query(l,mid,ql,qr,lson));
res=min(res,query(mid+1,r,ql,qr,rson));
return res;
}
}T;
void dfs1(int u,int ft,int dp){//第一遍dfs,求出sz,fa,dep,son
sz[u]=1;
fa[u]=ft;
dep[u]=dp;
int maxson=-1;
for(int e=H[u];e;e=E[e].nt){
int v=E[e].to;
if(v==fa[u]) continue;
dfs1(v,u,dp+1);
sz[u]+=sz[v];
if(sz[v]>maxson) maxson=sz[v],son[u]=v;
}
}
void dfs2(int u,int tp){//第二遍求出top,idx,val,并且将所有的节点通过轻重关系化成平面上的链
top[u]=tp;
idx[u]=++tot;
val[tot]=a[u];
if(!son[u]) return;
dfs2(son[u],tp);
for(int e=H[u];e;e=E[e].nt){
int v=E[e].to;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void Update(int a,int b,int v){//修改树上路径
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]]) swap(a,b);
T.update(1,n,idx[top[a]],idx[a],v,1);
a=fa[top[a]];
}
if(dep[a]>dep[b]) swap(a,b);
T.update(1,n,idx[a],idx[b],v,1);
}
int Lca(int x,int y){//求lca
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<=dep[y]?x:y;
}
int Query(int u){//查询操作
if(u==rt) return T.tr[1];
int lca=Lca(u,rt);
if(lca!=u) return T.query(1,n,idx[u],idx[u]+sz[u]-1,1);
int y;
for(int e=H[u];e;e=E[e].nt){
int v=E[e].to;
if(idx[v]<=idx[rt]&&idx[v]+sz[v]-1>=idx[rt]){y=v;break;}//找到root所在子树
}
int res=T.query(1,n,1,idx[y]-1,1); res=min(res,T.query(1,n,idx[y]+sz[y],n,1));
return res;
}
int main(){
tot=0,cnt=0;
n=read(),m=read();
for(int i=1;i<n;i++) addedge(read(),read());
for(int i=1;i<=n;i++) a[i]=read();
rt=read();
dfs1(1,-1,1); dfs2(1,1);
T.build(1,n,1,val);
while(m--){
int opt=read();
if(opt==1) rt=read();
if(opt==2){
int a=read(),b=read(),c=read();
Update(a,b,c);
}
if(opt==3){
int x=read();
printf("%d\n",Query(x));
}
}
return 0;
}
[luogu3979][bzoj3083]遥远的国度的更多相关文章
- BZOJ3083 遥远的国度 【树链剖分】
BZOJ3083 遥远的国度 Description zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcw ...
- bzoj3083 遥远的国度 && bzoj3626 LCA (树链剖分)
今早刷了两道树剖的题目,用时两小时十五分钟= = 树剖的题目代码量普遍120+ 其实打熟练之后是很容易调的,不熟练的话代码量大可能会因为某些小细节调很久 3083:裸树剖+"换根" ...
- 2018.06.30 BZOJ3083: 遥远的国度(换根树剖)
3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 512 MB Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国 ...
- BZOJ3083 遥远的国度(树链剖分+线段树)
考虑暴力树剖.那么修改路径和查询子树最小值非常简单. 对于换根当然不能真的给他转一下,我们只记录当前根是哪个.对于查询,如果查询点不在当前根到原根的路径上,显然换根是对答案没有影响的:如果是当前根,答 ...
- 【树链剖分】【线段树】bzoj3083 遥远的国度
记最开始的根为root,换根之后,对于当前的根rtnow和询问子树U而言, ①rtnow==U,询问整棵树 ②fa[rtnow]==U,询问除了rtnow所在子树以外的整棵树 ③rtnow在U的子树里 ...
- BZOJ3083 遥远的国度 【树剖】
题目 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务 ...
- BZOJ3083: 遥远的国度
传送门 BZOJ100题辣(已经无法直视的正确率 树剖板子题,注意和dfs序结合,根据根的变化变换统计的方式即可. //BZOJ 3083 //by Cydiater //2016.10.23 #in ...
- BZOJ3083——遥远的国度
1.题目大意:三个操作,换根,修改树上的某条路径,查询一个子树的最小值 2.分析:这个其实还是挺好做的,修改树上的某条路径,裸树剖,查询子树的最小值,这个是树剖满足dfs序 那么就是换根了,对吧,其实 ...
- bzoj3083 遥远的国度 题解
题目大意: 给定一棵有根树,每个点有一个权值,提供三种操作: 1.将x节点变为根节点 2.将x到y路径上的点的权值全部改为v 3.询问x的子树中点权的最小值 思路: 用DFS序剖分,记录每个节点入栈出 ...
随机推荐
- javascript中forEach()和jquery中each()的区别
forEach是ES5中操作数组的一种方法,主要功能是遍历数组 1.forEach方法中的function回调有三个参数:第一个参数是遍历的数组内容,第二个参数是对应的数组索引,第三个参数是数组本身 ...
- 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--请求处理结果适配篇(7/8)
文章目录 前情概要 前面一大坨一大坨的代码把route.controller.action.attribute都搞完事儿了,最后剩下一部分功能就是串起来的调用. 那接下就说个说第二个中间件,也是最后一 ...
- iphone忘记锁屏密码却记得appleID密码的不保存数据的刷机办法
请注意看清题目再看本文,另外一切后果博主不负任何责任.操作实现环境:原装数据线,拔掉sim卡昨天,iPhone6sp忘记密码被锁定,尝试通过找回手机抹除手机功能后,提示需要手机接入互联网才能实现,而我 ...
- 第三次作业(1) Visual Studio程序安装过程和练习过程
Visual Studio程序安装过程和练习过程 第一步 首先要在网上找一个VS2013的安装包,之后我安装在D盘上,C盘上也需要有5.2G空间,勾选相应的选项,才能继续安装. 安装的过程很漫长,接近 ...
- Microsoft Visual Studio 2013安装及试用
我是在网上下载的vs2013版的安装包,下载的是压缩文件,解压后是2.86GB.安装包下载完成后我们就可以进入安装了. 同时建议最好在互联网连接的情况下安装. 打开下载好的文件,我们要选择.exe可执 ...
- 《Linux内核设计与实现》读书笔记三
Chapter 18 调 试 18.1 准备开始 1.准备工作: 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 2.执行foo就会让程序立即产生核心信息转储(dump core). ...
- Alpha 答辩总结模板
Alpha 答辩总结模板 每个小组提供一篇总结博客(组内共享,每个人都发布),包含: 本组(组名)所有成员(短学号,名,标注组长)(1分) 组内各成员贡献比例,如不提供,取平均分后组长得分减50% G ...
- eclipse新建maven项目,修改默认jdk版本
我们新建maven项目,默认jdk版本是1.5,我们可以修改成我们想要的版本,有两种方法 1每个项目修改,在pom.xml添加 <build> <plugins> <!- ...
- HDU 2087 剪花布条 (字符串哈希)
http://acm.hdu.edu.cn/showproblem.php?pid=2087 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图 ...
- IIS7开启gZip动态压缩
1.安装动态压缩模块: 安装过程可能的报错:This application has requested the Runtime to terminate it in an unusual way. ...