zoukankan      html  css  js  c++  java
  • BZOJ 3306 树

    3306: 树

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 1451  Solved: 475
    [Submit][Status][Discuss]

    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

    Source

    我们先以1为根dfs并建立倍增数组,然后如果根换成了rt,然后要查询x子树内的最小值。我们分情况讨论:

    1)若x==rt,则直接输出整棵树的最小值

    2)若lca(x,rt)既不等于x那么直接输出x的子树内的最小值

    3)若lca(x,rt)==x那么我们发现整棵树除了x向下走可以到达rt的子树之外全部成了x在rt为根下的子树,那我们把这棵子树中最接近x的节点y求出,在整个区间中踢掉y在1根下子树的范围即可。

    #include <bits/stdc++.h>
    #define ll long long
    #define eps 1e-7
    #define inf 100000000
    using namespace std;
    inline int read(){
    	int x=0;int f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MAXN=1e6+10;
    struct node{
    	int y,next;
    }e[MAXN];
    struct sigment_tree{
    	int mn;
    }T[MAXN*4];
    int linkk[MAXN],len,n,m,in[MAXN],out[MAXN],dfs_clock,dep[MAXN],f[MAXN][25],rt,x,y,val[MAXN],ine[MAXN];
    inline void insert(int xx,int yy){
    	e[++len].y=yy;e[len].next=linkk[xx];linkk[xx]=len;
    }
    inline void dfs(int st,int fa){
    	in[st]=++dfs_clock;dep[st]=dep[fa]+1;f[st][0]=fa;ine[dfs_clock]=st;
    	for(int i=linkk[st];i;i=e[i].next){
    			dfs(e[i].y,st);
    	}
    	out[st]=dfs_clock;
    }
    void getanser(){
    	for(int i=1;i<=20;i++){
    		for(int j=1;j<=n;j++){
    			if(f[j][i-1]) f[j][i]=f[f[j][i-1]][i-1];
    		}
    	}
    }
    inline void add(int l,int r,int root){
    	if(l>x||r<x) return;
    	if(l==r){
    		T[root].mn=y;return;
    	}
    	int mid=(r+l)>>1;
    	add(l,mid,root<<1);
    	add(mid+1,r,root<<1|1);
    	T[root].mn=min(T[root<<1].mn,T[root<<1|1].mn);
    }
    inline void build(int l,int r,int root){
    	if(l==r){
    		T[root].mn=val[ine[l]];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,root<<1);
    	build(mid+1,r,root<<1|1);
    	T[root].mn=min(T[root<<1].mn,T[root<<1|1].mn);
    }
    inline int query(int l,int r,int root){
    	if(l>y||r<x) return inf;
    	int mid=(l+r)>>1;
    	if(x<=l&&y>=r) return T[root].mn;
    	return min(query(l,mid,root<<1),query(mid+1,r,root<<1|1));
    }
    void init(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		int xx=read();val[i]=read();
    		if(xx) insert(xx,i);
    	}
    	dfs(rt=1,0);
    	build(1,n,1);
    	getanser();
    }
    void solve(){
    	for(int i=1;i<=m;i++){
    		char ch[5];
    		scanf("%s",ch);x=read();
    		if(ch[0]=='V'){
    			x=in[x];y=read();
    			add(1,n,1);
    		}
    		else if(ch[0]=='E') rt=x;
    		else{
    			if(rt==x) printf("%d
    ",T[1].mn);
    			else{
    				if(in[x]<=in[rt]&&out[x]>=out[rt]){
    					int depth=dep[rt]-dep[x]-1;int yy=rt;
    					for(int i=20;i>=0;i--){
    						if(depth-(1<<i)>=0) yy=f[yy][i],depth-=(1<<i);
    					}
    					x=1;y=in[yy]-1;
    					int minn=query(1,n,1);
    					x=out[yy]+1;y=n;
    					minn=min(minn,query(1,n,1));
    					printf("%d
    ",minn);
    				}
    				else{
    					y=out[x];x=in[x];
    					printf("%d
    ",query(1,n,1));
    				}
    			}
    		}
    	}
    }
    int main(){
    	//freopen("All.in","r",stdin);
    	//freopen("ba.out","w",stdout);
    	init();
    	solve();
    	return 0;
    }
    

    对拍代码

    #include <bits/stdc++.h>
    using namespace std;
    int main(){
    	srand(time(int(NULL)));
    	freopen("All.in","w",stdout);
    	int n=rand()%10007;int m=rand()%10007;
    	cout<<n<<' '<<m<<endl;
    	cout<<0<<' '<<rand()%10007<<endl;
    	for(int i=2;i<=n;i++){
    		int k=rand()%i;if(!k) k++;
    		printf("%d %d
    ",k,rand()%10007);
    	}
    	for(int i=1;i<=m;i++){
    		int k=rand()%3;
    		if(k==0){
    			printf("V %d %d
    ",rand()%n+1,rand()%10007);
    		}
    		if(k==1) printf("Q %d
    ",rand()%n+1);
    		if(k==2) printf("E %d
    ",rand()%n+1);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    break return continue
    爬虫---请求
    pycharm加开头注释
    爬虫---入门
    pip
    XML基础
    英语
    布局
    adobe
    StackOverflow
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/8168968.html
Copyright © 2011-2022 走看看