Description

给定一棵大小为 n 的有根点权树,支持以下操作: 
  • 换根 
  • 修改点权  
     • 查询子树最小值

Input

  第一行两个整数 n, Q ,分别表示树的大小和操作数。 
  接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。 
  接下来 m 行,为以下格式中的一种: 
  • V x y表示把点x的权改为y 
  • E x 表示把有根树的根改为点 x 
  • Q x 表示查询点 x 的子树最小值

Output

  对于每个 Q ,输出子树最小值。

Sample Input

3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1

Sample Output

1
2
3
4

HINT

  对于 100% 的数据:n, Q ≤ 10^5。

题解:

  蛮裸的一道题(但我线段树打错,一路狂wa……)

  跑dfs序,用线段树维护dfs序区间最值。对于x与root的关系:

1.x==root ,全局最小

2.x为root祖先节点,找到x的某个包含root的儿子,查询除去这个儿子以为的全局最值

3.其他情况下,直接查询x子树最值。

代码:

 #include<cstdio>
inline int min(int a,int b){return a<b?a:b;}
const int N=(int )1e5+;
inline int read(){
int s=,k=;char ch=getchar();
while(ch<''||ch>'') k=ch=='-'?-:k,ch=getchar();
while(ch>&&ch<='') s=s*+(ch^),ch=getchar();
return s*k;
}
int n,Q;
struct edges{
int v;edges *last;
}edge[N],*head[N];int cnt;
inline void push(int u,int v){
edge[++cnt]=(edges){v,head[u]};head[u]=edge+cnt;
}
struct Tree{
int val;Tree *son[];
Tree(){
son[]=son[]=NULL;
}
}tree[N<<],*root;
int val[N];
int rt;
int f[][N],deep[N];
int l[N],r[N],re[N];
int num;
inline void dfs(int x){
l[x]=++num;
re[num]=x;
for(int i=;(<<i)<=deep[x];i++)
f[i][x]=f[i-][f[i-][x]];
for(edges *i=head[x];i;i=i->last){
deep[i->v]=deep[x]+;
f[][i->v]=x;
dfs(i->v);
}
r[x]=num;
}
inline int LCA(int x,int y){
if(deep[x]<deep[y]) x^=y^=x^=y;
int t=deep[x]-deep[y];
for(int i=;t;i++) if(t&(<<i)){
t^=(<<i);
x=f[i][x];
}
if(x==y) return x;
for(int i=;i>=;i--){
if(f[i][x]!=f[i][y])
x=f[i][x],y=f[i][y];
}return f[][x];
}
inline void build(Tree *&u,int l,int r){
u=tree+cnt;
cnt++;
if(l==r){
u->val=val[re[l]];return ;
}
int mid=l+r>>;
build(u->son[],l,mid);
build(u->son[],mid+,r);
u->val=min(u->son[]->val,u->son[]->val);
//printf("l=%d r=%d val=%d son[0]=%d son[1]=%d\n",l,r,u->val,u->son[0]->val,u->son[1]->val);
} inline void add(Tree *u,int l,int r,int x,int w){
if(l==r){
u->val=w;return ;
}
int mid=l+r>>;
if(x>mid) add(u->son[],mid+,r,x,w);
else add(u->son[],l,mid,x,w);
u->val=min(u->son[]->val,u->son[]->val);
} inline int query(Tree *u,int l,int r,int x,int y){
if(x>y) return 0x7fffffff;
if(x<=l&&r<=y){
return u->val;
}
int mid=l+r>>;
if(x>mid) return query(u->son[],mid+,r,x,y);
else if(y<=mid) return query(u->son[],l,mid,x,y);
return min(query(u->son[],l,mid,x,y),query(u->son[],mid+,r,x,y));
}
int main(){
n=read(),Q=read();
for(int i=;i<=n;i++){
int x=read();
if(x==) rt=i;
val[i]=read();push(x,i);
}
dfs(rt);
cnt=;
build(root,,n);
char op[];
while(Q--){
scanf("%s",op);
if(op[]=='V'){
int x=read(),y=read();
add(root,,n,l[x],y);
}else if(op[]=='E'){
int x=read();
rt=x;
}else{
int x=read();
if(rt==x){
printf("%d\n",root->val);
continue;
}
if(l[x]<=l[rt]&&r[x]>=r[rt]){
int y=rt;
int t=deep[rt]-deep[x]-;
for(int i=;t;i++)if(t&(<<i)){
t^=<<i;
y=f[i][y];
}
printf("%d\n",min(query(root,,n,,l[y]-),query(root,,n,r[y]+,n)));
}else{
printf("%d\n",query(root,,n,l[x],r[x]));
}
}
}
}
/*
3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1
*/

【bzoj 3306】树的更多相关文章

  1. BZOJ 3306 树

    dfs序建线段树+分类讨论+写的有点长. #include<iostream> #include<cstdio> #include<cstring> #includ ...

  2. BZOJ 3306: 树 LCT + set 维护子树信息

    可以作为 LCT 维护子树信息的模板,写的还是比较优美的. 本地可过,bzoj 时限太紧,一直 TLE #include<bits/stdc++.h> #define setIO(s) f ...

  3. bzoj 3306

    以1号节点为根,弄出DFS序,我们发现,对于一个询问:(rt,u),以rt为根,u节点的子树中的最小点权,我们可以根据rt,u,1这三个节点在同一条路径上的相对关系来把它转化为以1为根的在DFS序上的 ...

  4. bzoj 3196 树套树模板

    然而我还是在继续刷水题... 终于解开了区间第k大的心结... 比较裸的线段树套平衡树,比较不好想的是求区间第k大时需要二分一下答案,然后问题就转化为了第一个操作.复杂度nlog3n.跑的比较慢... ...

  5. BZOJ 1969 树链剖分+Tarjan缩点

    发现自己Tarjan的板子有错误.发现可以用Map直接删去边,Get. 听说std是双连通.LCA.并查集.离线思想.用BIT维护dfs序和并查集维护LCA的动态缩点的好题 #include < ...

  6. BZOJ 2286 树链剖分+DFS序+虚树+树形DP

    第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. #include <iostream> #include <cstring> #include <cstdio& ...

  7. BZOJ 4326 树链剖分+二分+差分+记忆化

    去年NOIP的时候我还不会树链剖分! 还是被UOJ 的数据卡了一组. 差分的思想还是很神啊! #include <iostream> #include <cstring> #i ...

  8. BZOJ 3110 树套树 && 永久化标记

    感觉树套树是个非常高深的数据结构.从来没写过 #include <iostream> #include <cstdio> #include <algorithm> ...

  9. BZOJ 2282 & 树的直径

    SDOI2011的Dayx第2题 题意: 在树中找到一条权值和不超过S的链(为什么是链呢,因为题目中提到“使得路径的两端都是城市”,如果不是链那不就不止两端了吗——怎么这么机智的感觉...),使得不在 ...

随机推荐

  1. python标准库Beautiful Soup与MongoDb爬喜马拉雅电台的总结

    Beautiful Soup标准库是一个可以从HTML/XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,Beautiful Soup将会节省数小 ...

  2. Web服务器Tomcat集群与负载均衡技术

    我们曾经介绍过三种Tomcat集群方式的优缺点分析.本文将介绍Tomcat集群与负载均衡技术具体实施过程. 在进入集群系统架构探讨之前,先定义一些专门术语: 1. 集群(Cluster):是一组独立的 ...

  3. Java——接口

    被interface修饰的类,叫接口接口里的方法都是抽象的,不能实现.用implements关键字可以让一个类来实现该接口.接口:一个类在继承另一个类的同时.还可以实现多个接口.接口的出现避免了单继承 ...

  4. profile bashrc bash_profile之间的区别和联系

    profile bashrc bash_profile之间的区别和联系 博客分类: Linux   执行顺序为:/etc/profile -> (~/.bash_profile | ~/.bas ...

  5. Day7 子类调用父类的方法supper 绑定方法与非绑定方法

    supper:可以利用supper来重用父类的方法,可以不用指名道姓的调用了. class OldboyPeople: school = 'oldboy' def __init__(self,name ...

  6. TensorFlow实践笔记(一):数据读取

    本文整理了TensorFlow中的数据读取方法,在TensorFlow中主要有三种方法读取数据: Feeding:由Python提供数据. Preloaded data:预加载数据. Reading ...

  7. 兼容 Android 4.4 透明状态栏与导航栏

    http://www.apkbus.com/Android-163388-1-1.html?_dsign=73d41229 android 系统自4.2 开始 UI 上就没多大改变,4.4 也只是增加 ...

  8. Git忽略远程已存在的文件

    git设置本地忽略时远程上不存在本地忽略的文件,git将忽略.如果远程分支上存在这个文件,本地在设置ignore将不起作用.换句话说git本地忽略文件必须保证git的远程仓库分支上没有这个要忽略的文件 ...

  9. Node笔记一

    什么是javascript? --脚本语言 --运行在浏览器中 --一般用来做客户端页面的交互 javascript运行环境 --运行在浏览器内核中的JS引擎 浏览器这种javascript可以做什么 ...

  10. 初探Margin负值(转)

    相对而言,margin 负值的使用机率在布局中似乎很少,但是我相信一旦你开始掌握就会着迷,接下来我们看看关于margin负值的一些资料: 它是一个有效的属性,至少w3c中明确描述如下:”Negativ ...