【BZOJ 3306】树

良心的笔者直接给出了题面:

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。

解法:

         首先,全程用线段树/树状数组维护。可以记录每个节点在dfs序中的编号,以此将一个子树中的所有节点转换成区间上的连续的一段。

         对于操作1,我们正常地单点修改

         对于操作2,计一个变量表示现在的根节点的编号。

         对于操作3,如果当前查询的x不是根节点的祖先,那就正常的区间查询,

                             否则,我们修改除该子树外,所有的点。(可以画图证明一下,可好玩了~~)

/*
	Name: shu
	Copyright: author's
	Author: wangziyao
	Date: 22/01/19 19:01
	Description: BZOJ3306
*/
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rep2(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
template<typename T> void read(T &num){
	char c=getchar();num=0;T f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
	num*=f;
}
template<typename T> void qwq(T x){
	if(x>9)qwq(x/10);
	putchar(x%10+'0');
}
template<typename T> void write(T x){
	if(x<0){x=-x;putchar('-');}
	qwq(x);putchar('\n');
}
template<typename T> void chkmin(T &x,T y){x=x<y?x:y;}
int n,q;
struct wzy{
	int nxt,vertice;
}edge[100010];
int head[100010];int len=0;
inline void add_edge(int x,int y){
	edge[++len].nxt=head[x];edge[len].vertice=y;head[x]=len;return;
}
int id[100010];int siz[100010];int tot=0;int num[100010];
int f[100010][17];int dep[100010];
inline void Pretreatment(int son,int father){
	siz[son]=1;id[son]=++tot;f[son][0]=father;dep[son]=dep[father]+1;num[tot]=son;
	rep(i,1,16){f[son][i]=f[f[son][i-1]][i-1];}
	for(int i=head[son];i;i=edge[i].nxt){
		int nop=edge[i].vertice;
		Pretreatment(nop,son);siz[son]+=siz[nop];
	}
	return;
}
int lans=0;
inline int LCA(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	rep2(i,16,0){if(dep[f[x][i]]>dep[y]){x=f[x][i];}}
	if(f[x][0]==y){lans=x;return y;}
	rep2(i,16,0){if(f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];}}
	return f[x][0];
}

int co[100010];int val[400010];
inline void build(int ll,int rr,int pos){
	if(ll>rr)return;
	if(ll==rr){val[pos]=co[num[ll]];return;}
	int mid=(ll+rr)>>1;
	build(ll,mid,pos<<1);build(mid+1,rr,pos<<1|1);
	val[pos]=min(val[pos<<1],val[pos<<1|1]);return;
}
inline void change(int l,int r,int cl,int cw,int pos){
	if(l>r)return;
	if(l==r){val[pos]=cw;return;}
	int mid=(l+r)>>1;
	if(cl<=mid){change(l,mid,cl,cw,pos<<1);}
	else{change(mid+1,r,cl,cw,pos<<1|1);}
	val[pos]=min(val[pos<<1],val[pos<<1|1]);
	return; 
}
inline int query(int l,int r,int ql,int qr,int pos){
	if(l>r)return 0;
	if(ql<=l&&r<=qr){return val[pos];}
	else{
		int mid=(l+r)>>1;int ans=INT_MAX;
		if(ql<=mid)chkmin(ans,query(l,mid,ql,qr,pos<<1));
		if(qr>mid)chkmin(ans,query(mid+1,r,ql,qr,pos<<1|1));
		return ans;
	}
}

int main(){
	read(n);read(q);
	rep(i,1,n){int f,v;read(f);read(v);add_edge(f,i);co[i]=v;} 
	Pretreatment(1,0);build(1,n,1);
	
	int root=1;
	rep(i,1,q){
		char ch;int x,y;cin>>ch;read(x);
		if(ch=='V'){
			read(y);change(1,n,id[x],y,1);
		}else if(ch=='E'){
			root=x;
		}else{
			int temp=LCA(x,root);
			if(x==root){write(query(1,n,1,n,1));continue;}
			if(temp!=x){write(query(1,n,id[x],id[x]+siz[x]-1,1));}
			else{write(min(query(1,n,1,id[lans]-1,1),query(1,n,id[lans]+siz[lans],n,1)));}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Bill_Benation/article/details/86608329