树 bzoj-3306

题目大意:给定一颗n个节点的树,支持换根、修改点权、查询子树最小值。

注释:$1\le n,q\le 10^5$。


想法

如果没有换根操作,就是$dfs$序+线段树维护区间最小值即可。

加入有换根操作,我们发现对修改操作没影响。

我们只需要判断一下询问的点和当前根的关系即可。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls p<<1
#define rs p<<1|1
#define N 100010
using namespace std;
int to[N<<1],nxt[N<<1],tot,head[N];
int f[21][N],dic[N],re[N],size[N],dep[N],cnt,mn[N<<2],val[N],root;
inline void add(int x,int y) {to[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}
void dfs(int pos,int fa)
{
dic[pos]=++cnt; re[cnt]=pos; f[0][pos]=fa; for(int i=1;i<=20;i++) f[i][pos]=f[i-1][f[i-1][pos]];
dep[pos]=dep[fa]+1; size[pos]=1; for(int i=head[pos];i;i=nxt[i]) if(to[i]!=fa)
{
dfs(to[i],pos);
size[pos]+=size[to[i]];
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;~i;i--) if(dep[f[i][x]]>=dep[y]) x=f[i][x];
if(x==y) return x;
for(int i=20;~i;i--) if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
int get_lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;~i;i--) if(dep[f[i][x]]>dep[y]) x=f[i][x];
return x;
}
inline void pushup(int p)
{
mn[p]=min(mn[ls],mn[rs]);
}
void build(int l,int r,int p)
{
if(l==r) {mn[p]=val[re[l]]; return;}
int mid=(l+r)>>1;
build(l,mid,ls); build(mid+1,r,rs);
pushup(p);
}
void update(int x,int v,int l,int r,int p)
{
if(l==r) {mn[p]=v; return;}
int mid=(l+r)>>1;
if(x<=mid) update(x,v,l,mid,ls);
else update(x,v,mid+1,r,rs);
pushup(p);
}
int query(int x,int y,int l,int r,int p)
{
if(x<=l&&r<=y) return mn[p];
int mid=(l+r)>>1,ans=0x7f7f7f7f;
if(x<=mid) ans=min(ans,query(x,y,l,mid,ls));
if(mid<y) ans=min(ans,query(x,y,mid+1,r,rs));
return ans;
}
int main()
{
int x,y,n,m; scanf("%d%d",&n,&m); char opt[10]; for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
if(!x) root=i;
else add(i,x),add(x,i);
val[i]=y;
}
dfs(root,root);
// for(int i=1;i<=n;i++) printf("%d ",size[i]); puts("");
build(1,n,1);
for(int i=1;i<=m;i++)
{
scanf("%s%d",opt,&x);
if(opt[0]=='V')
{
scanf("%d",&y); update(dic[x],y,1,n,1);
}
else if(opt[0]=='E')
{
root=x;
}
else
{
if(x==root) printf("%d\n",query(1,n,1,n,1));
else if(lca(x,root)!=x) printf("%d\n",query(dic[x],dic[x]+size[x]-1,1,n,1));
else
{
int y=get_lca(root,x);
printf("%d\n",min(query(1,dic[y]-1,1,n,1),query(dic[y]+size[y],n,1,n,1)));
}
}
}
return 0;
}

小结:拟对象考虑问题有奇效。

[bzoj3306]树_dfs序_线段树_倍增lca的更多相关文章

  1. luogu1377 树的序 (线段树)

    题意:给你一个1~N的排列,然后让你按顺序把它们插到一个二叉搜索树里,然后问能插出同样的二叉搜索树的 字典序最小的排列是什么 本来可以直接模拟建树然后dfs一下输出结果...然而有可能会退化成链,最差 ...

  2. [bzoj3252]攻略_dfs序_线段树_贪心

    攻略 bzoj-3252 题目大意:给定一棵n个节点的有根树,点有点权.让你选出至多k个节点,使得他们到根的链的并最大. 注释:$1\le n\le 2\cdot 10^5$,$1\le val_i\ ...

  3. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  4. BZOJ_4636_蒟蒻的数列_线段树+动态开点

    BZOJ_4636_蒟蒻的数列_线段树+动态开点 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将 ...

  5. BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针

    BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间, ...

  6. BZOJ_2124_等差子序列_线段树+Hash

    BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...

  7. BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

    BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...

  8. BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树

    BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树 Description Input 第1行:两个用空格隔开的整数:N和M * 第2行到N+1行:第i+1行表示一个整数 ...

  9. BZOJ_1798_[AHOI2009]维护序列_线段树

    BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...

  10. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

随机推荐

  1. Docker Java+Tomcat 环境搭建

    软件环境:jdk.tomcat.docker.centos.虚拟机 首先,您要准备一个 CentOS 的操作系统,虚拟机也行.总之,可以通过 Linux 客户端工具访问到 CentOS 操作系统就行. ...

  2. Spark学习之Spark Streaming(9)

    Spark学习之Spark Streaming(9) 1. Spark Streaming允许用户使用一套和批处理非常接近的API来编写流式计算应用,这就可以大量重用批处理应用的技术甚至代码. 2. ...

  3. TCP/UDP套接字 java socket编程实例

    网络协议七层结构: 什么是Socket? socket(套接字)是两个程序之间通过双向信道进行数据交换的端,可以理解为接口.使用socket编程也称为网络编程,socket只是接口并不是网络通信协议. ...

  4. OC中文件读取类(NSFileHandle)介绍和常用使用方法

    NSFileHandle 1.NSFileManager类主要对于文件的操作(删除,修改,移动,赋值等等) //判断是否有 tagetPath 文件路径,没有就创建 NSFileManager *fi ...

  5. SweetAlert如何实现点击Confirm之后自动关闭

    swal({ title: "Are you sure?", text: "You will not be able to recover this imaginary ...

  6. Python2和Python3除法

    Python2和Python3除法   Python2除法:/,//,% "/":整数相除,向下取整:浮点数相除,结果包含小数(类似1/2,想保留小数应该写成1.0/2或者1*1. ...

  7. 使用Latex插入数学公式(二)

    初级运算 关系运算符 希腊字母 集合运算符逻辑运算符 空格问题 矩阵格式 矩阵格式有三种: 无括号的矩阵 matrix 是 Latex 的矩阵命令,矩阵命令中每一行以 \\ 结束,矩阵的元素之间用 & ...

  8. CE工具里自带的学习工具--第一关

    点击[下一步],进入第二关

  9. 并发2-Synchronized

    一.Synchronized的概念 是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个 ...

  10. Python轮换

    switch_source()用于获取文本信息rewrite_source()用于将信息顺序轮换,其参数times表示要轮换多少次, def switch_source(): tmp = [] wit ...