zoukankan      html  css  js  c++  java
  • CF1137FMatches Are Not a Child‘s Play【LCT】

    正题

    题目链接:https://www.luogu.com.cn/problem/CF1137F


    题目大意

    给出\(n\)个点的一棵树,第\(i\)个点权值为\(i\)

    一棵树的删除序列定义为每次删除编号最小的叶子并将其加入序列末尾。

    要求支持

    1. 修改一个点的权值为一个比目前所有权值都要大的一个值
    2. 询问一个点在删除序列的位置
    3. 询问两个点在删除序列的先后顺序

    \(1\leq n,q\leq 2\times 10^5\)


    解题思路

    假设我们已经确定的先后顺序,目前最大的权值为\(y\)号点,然后修改一个点\(x\)时相当于把\(y\sim x\)的路径上所有点依次放在序列末尾。

    相当于我们要支持提出一条树链,可以考虑用\(LCT\)实现。

    以权值最大的点为根,我们对于每一条树链(splay)附上同一个颜色,那么一个点的答案就是颜色编号比它小的点数+所在树链上深度比它小的点数+1。

    然后修改就相当于连接+换根+换颜色。颜色方面可以用树状数组维护前缀和,然后再\(Access\)的时候进行修改,换根也是可以用\(LCT\)做到的。

    时间复杂度\(O(n\log^2 n)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stack>
    #define lowbit(x) (x&-x)
    using namespace std;
    const int N=2e5+10;
    struct node{
    	int to,next;
    }a[N<<1];
    int n,q,cnt,tot,ls[N],col[N];
    struct BinaryInTree{
    	int t[N<<1],n;
    	void Change(int x,int val){
    		while(x<=n){
    			t[x]+=val;
    			x+=lowbit(x);
    		}
    		return;
    	}
    	int Ask(int x){
    		int ans=0;
    		while(x){
    			ans+=t[x];
    			x-=lowbit(x);
    		}
    		return ans;
    	}
    }B;
    struct LCT{
    	int fa[N],t[N][2],siz[N];
    	bool r[N];stack<int> s;
    	bool Nroot(int x)
    	{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
    	bool Direct(int x)
    	{return t[fa[x]][1]==x;}
    	void PushUp(int x)
    	{siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;return;}
    	void Rev(int x)
    	{r[x]^=1;swap(t[x][0],t[x][1]);return;}
    	void PushDown(int x){
    		if(t[x][0])col[t[x][0]]=col[x];
    		if(t[x][1])col[t[x][1]]=col[x];
    		if(!r[x])return;
    		Rev(t[x][0]);Rev(t[x][1]);
    		r[x]=0;return;
    	}
    	void Rotate(int x){
    		int y=fa[x],z=fa[y];
    		int xs=Direct(x),ys=Direct(y);
    		int w=t[x][xs^1];
    		if(Nroot(y))t[z][ys]=x;
    		t[y][xs]=w;t[x][xs^1]=y;
    		if(w)fa[w]=y;fa[y]=x;fa[x]=z;
    		PushUp(y);PushUp(x);return;
    	}
    	void Splay(int x){
    		int y=x;s.push(x);
    		while(Nroot(y))y=fa[y],s.push(y);
    		while(!s.empty())PushDown(s.top()),s.pop();
    		while(Nroot(x)){
    			int y=fa[x];
    			if(!Nroot(y))Rotate(x);
    			else if(Direct(x)==Direct(y))
    				Rotate(y),Rotate(x);
    			else Rotate(x),Rotate(x);
    		}
    		return;
    	}
    	void Access(int x){
    		for(int y=0;x;y=x,x=fa[x]){
    			Splay(x);t[x][1]=0;PushUp(x);
    			B.Change(col[x],-siz[x]);
    			B.Change(cnt,siz[x]);
    			t[x][1]=y;PushUp(x);
    		}
    		return;
    	}
    	void MakeRoot(int x){
    		++cnt;Access(x);
    		Splay(x);col[x]=cnt;
    		Rev(x);return;
    	}
    	int Ask(int x){
    		Splay(x);
    		return siz[t[x][1]]+1+B.Ask(col[x]-1);
    	}
    }T;
    void addl(int x,int y){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;return;
    }
    void dfs(int x){
    	col[x]=x;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		if(y==T.fa[x])continue;
    		T.fa[y]=x;dfs(y);
    		if(col[y]>col[x]){
    			col[x]=col[y];
    			T.t[x][1]=y;
    		}
    	}
    	B.Change(col[x],1);
    	T.PushUp(x);
    }
    int main()
    {
    	scanf("%d%d",&n,&q);
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		addl(x,y);addl(y,x);
    	}
    	B.n=n+q;cnt=n;dfs(n);
    	for(int i=1;i<=q;i++){
    		char op[6];int x,y;
    		scanf("%s%d",op,&x);
    		if(op[0]=='u')T.MakeRoot(x);
    		else if(op[0]=='w')
    			printf("%d\n",T.Ask(x));
    		else if(op[0]=='c'){
    			scanf("%d",&y);
    			int l=T.Ask(x),r=T.Ask(y);
    			if(l<r)printf("%d\n",x);
    			else printf("%d\n",y);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    HTTP协议详解(真的很经典)
    几点建议,让Redis在你的系统中发挥更大作用
    Redis能干啥?细看11种Web应用场景
    Java中使用Jedis操作Redis
    java的锁机制——synchronized
    web开发中的两把锁之数据库锁:(高并发--乐观锁、悲观锁)
    一分钟教你知道乐观锁和悲观锁的区别
    $^,$@,$?,$<,$(@D),$(@F) of makefile
    linux shared lib 使用与编译
    makefile learning
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14451636.html
Copyright © 2011-2022 走看看