zoukankan      html  css  js  c++  java
  • CF1137F Matches Are Not a Child's Play

    我们定义一棵树的删除序列为:每一次将树中编号最小的叶子删掉,将该节点编号加入到当前序列的最末端,最后只剩下一个节点时将该节点的编号加入到结尾。现在给出一棵n个节点的树,有m次操作:

    up v:将v号节点的编号变为当前所有节点编号的(max + 1)

    when v:查询v在当前树的删除序列中是第几号元素

    compare u v:查询u和v在当前树的删除序列中谁更靠前

    题解

    考虑每个点up后会带来什么影响。

    可以发现新修改的这个点和修改这个点之前编号最大的点之间的这条链是最后被删掉的。

    而且删除的顺序是有序的。

    把这条链删掉之后,其他的链之间的删除顺序是不变的。

    所以我们可以考虑维护这些链。

    如果每次令最大的点为根,那么每次的操作相当于是(makeroot)

    这里我们还需要给每条链赋一个权值,为删除顺序当中的优先度,这个可以在(LCT)上打标记。

    还有一个问题就是如何维护一开始的删除序列。

    这个其实(dfs)一遍就可以了,先令每个点的权值为自己的编号,然后自底向上更新,如果儿子的比父亲的大就用儿子去更新父亲。

    代码

    #include<bits/stdc++.h>
    #define N 200009
    #define ls ch[x][0]
    #define rs ch[x][1]
    using namespace std;
    typedef long long ll;
    char s[10];
    int ch[N][2],fa[N],n,q,head[N],tot,size[N],col[N],now,rev[N],maxn;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    struct edge{
    	int n,to;
    }e[N<<1];
    struct BIT{
    	int tr[N<<1];
    	inline void add(int x,int y){while(x<=maxn)tr[x]+=y,x+=x&-x;}//!!!!!!!!!!
    	inline int query(int x){int ans=0;while(x)ans+=tr[x],x-=x&-x;return ans;}
    }tr;
    inline bool ge(int x){return ch[fa[x]][1]==x;}
    inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    inline void pushup(int x){size[x]=size[ls]+size[rs]+1;}
    inline void rotate(int x){
    	int y=fa[x],o=ge(x);
    	ch[y][o]=ch[x][o^1];fa[ch[y][o]]=y;
    	if(!isroot(y))ch[fa[y]][ge(y)]=x;fa[x]=fa[y];
    	fa[y]=x;ch[x][o^1]=y;
    	pushup(y);pushup(x);
    }
    inline void pushdown(int x){
    	if(rev[x]){
           rev[ls]^=1;rev[rs]^=1;
           rev[x]^=1;
           swap(ls,rs); 
    	}  
    	if(ls)col[ls]=col[x];///!!!!!
        if(rs)col[rs]=col[x];
    }
    inline void _pushdown(int x){
    	if(!isroot(x))_pushdown(fa[x]);
    	pushdown(x);
    }
    inline void splay(int x){
    	_pushdown(x);
    	while(!isroot(x)){
    		int y=fa[x];
    		if(isroot(y))rotate(x);
    		else rotate(ge(x)==ge(y)?y:x),rotate(x);
    	}
    }
    inline void access(int x){
        for(int y=0;x;y=x,x=fa[x]){
        	splay(x);
            tr.add(col[x],-size[x]+size[rs]);
            tr.add(now,size[x]-size[rs]);
            ch[x][1]=y;pushup(x);
        }
    }
    inline void makeroot(int x){
    	++now;
    	access(x);splay(x);rev[x]^=1;col[x]=now;
    }
    inline void add(int u,int v){
    	e[++tot].n=head[u];e[tot].to=v;head[u]=tot;
    }
    int query(int x){
    	splay(x);
    	return tr.query(col[x]-1)+size[rs]+1;
    }
    void dfs(int u){
    	col[u]=u;
    	size[u]=1;
    	for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa[u]){
    		int v=e[i].to;fa[v]=u;
    		dfs(v);
            if(col[v]>col[u]){
            	col[u]=col[v];
            	ch[u][1]=v;
            	size[u]=size[v]+1;
            }
    	}
    	tr.add(col[u],1);
    }
    int main(){
    	n=rd();q=rd();
    	maxn=n+q;
    	int u,v,w;
    	now=n;
    	for(int i=1;i<n;++i){
    		u=rd();v=rd();
    		add(u,v);add(v,u);
    	}
    	dfs(n);
    	while(q--){
    		scanf("%s",s);
    		if(s[0]=='u'){
              u=rd();
              makeroot(u);
    		}
    		else if(s[0]=='w'){
              u=rd();
              printf("%d
    ",query(u));
    		}
    		else if(s[0]=='c'){
              u=rd();v=rd();
              printf("%d
    ",query(u)>query(v)?v:u);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    一、Java语言基础(2)_类型和运算——基本数据类型转换
    一、Java语言基础(2)_类型和运算——数据类型和分类
    一、Java语言基础(2)_类型和运算——字面量和常量
    一、Java语言基础(1)_走进java——基本语法
    接口测试彻底弄懂Session、Cookie、Token的区别及联系hold住面试官--hold住了开3万,hold不住开3K!
    待过猫厂、狗厂、鹅厂、猪厂的10年测试码农告诉你-测试计划与测试方案的区别?
    2020非常全的接口测试面试题及参考答案-软件测试工程师没有碰到算我输!
    2020非常全的软件测试linux常用命令全集,linux面试题及参考答案
    jmeter实现接口关联的两种方式:正则表达式提取器和json提取器看这篇就够了
    通过pycharm使用git和github的步骤(图文详解)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10882232.html
Copyright © 2011-2022 走看看