zoukankan      html  css  js  c++  java
  • 蒟蒻的splay2之文艺平衡树

    前情回顾:蒟蒻的splay1
    时隔好久终于更新了.jpg
    文艺平衡树
    简单来说就是要求区间翻转
    首先我们按照点的编号来建一颗二叉搜索树,建树方式类似线段树(注意空间要开大不然会(T)
    这样建出来的树类似这样:

    然后我们就可以在树上找到区间了
    但是我们怎么翻转呢?
    如果这个区间长度为2,那么我们可以暴力的(swap)
    如果长度更长呢?我们是不是可以按某种规则去(swap)?
    注意到如果将(l-1)(splay)到根,(r+1)(splay)到根的右儿子,则(r+1)的左子树就是我们要翻转的区间。然后翻转这个子树就可以了。
    如果暴力(swap)整颗子树,肯定会(T),而且某个点可能被翻转多次(即有可能最终位置不变),所以我们用标记来搞某个点是否翻转。这样翻转子树的时候只用搞搞标记再(swap)一下就(ok)
    来康康代码叭

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    inline int read()
    {
    	char ch=getchar();
    	int x=0;bool f=0;
    	while(ch>'9'||ch<'0')
    	{
    		if(ch=='-')f=1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<3)+(x<<1)+(ch^48);
    		ch=getchar();
    	}
    	return f?-x:x; 
    }
    const int inf=214748364;
    int n,m,sz;
    int key[1000100],val[100010],root,size[1000100],ch[1000100][2],tag[1000100],par[1001000];
    bool get(int x)
    {
    	return ch[par[x]][1]==x;
    }
    void pushup(int x)
    {
    	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
    }
    void pushdown(int x)//下放标记
    {
    	if(!x)return ;
    	if(!tag[x])return;
    	tag[ch[x][0]]^=1;
    	tag[ch[x][1]]^=1;
    	swap(ch[x][0],ch[x][1]);
    	tag[x]=0;
    	return ;
    }
    int build(int fa,int l,int r)//建树
    {
    	if(l>r) return 0;
    	sz++;
    	int now=sz;
    	int mid=(l+r)>>1;
    	key[now]=val[mid];
    	par[now]=fa;
    	ch[now][0]=build(now,l,mid-1);
    	ch[now][1]=build(now,mid+1,r);
    	pushup(now);
    	return now;
    }
    void rotate(int x)
    {
    	int y=par[x],z=par[y],k=get(x),e=get(y);
    	pushdown(y);pushdown(x);
    	ch[y][k]=ch[x][k^1];
    	par[ch[y][k]]=y;
    	ch[x][k^1]=y;par[y]=x;
    	par[x]=z;
    	if(z)
    	 ch[z][e]=x;
    	pushup(y);pushup(x);
    }
    void splay(int x,int goal)
    {
    	for(int fa;(fa=par[x])!=goal;rotate(x))
    	{
    		if(par[fa]!=goal)
    		  rotate((get(x)==get(fa))?fa:x);
    	}
    	if(!goal)root=x;
    }
    int rnk(int x)//查询某个点的排名 
    {
    	int now=root;
    	while(1)
    	{
    		pushdown(now);
    		if(x<=size[ch[now][0]])now=ch[now][0];
    		else
    		{
    			x-=size[ch[now][0]]+1;
    			if(!x)
    			{
    			return now;
    			}
    			now=ch[now][1];
    		}
    	}
    }
    void print(int now)//最终输出
    {
            pushdown(now);
    	if(ch[now][0])print(ch[now][0]);
    	if(key[now]!=inf&&key[now]!=-inf)printf("%d ",key[now]);
    	if(ch[now][1])print(ch[now][1]);
    }
    void fz(int l,int r)
    {
    	l=rnk(l);//因为有虚点,所以l是真正的l-1
    	r=rnk(r+2);//r+2同理
    	splay(l,0);
    	splay(r,l);
    	pushdown(root);
    	tag[ch[ch[root][1]][0]]^=1;//标记根的右儿子的左子树要翻转
    
    }
    
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    	 val[i+1]=i;
    	val[1]=-inf;val[n+2]=inf;//插入两个虚点防RE
    	root=build(0,1,n+2);
    	for(int i=1;i<=m;i++)
    	{
    		int l=read(),r=read();
                    fz(l,r);
    	}
    	print(root);
    }
    
  • 相关阅读:
    java中Logger.getLogger(Test.class),即log4日志的使用
    System.getProperty()方法大全 (转载)
    常用MySQL函数
    MYSQL常用命令(转载)
    Oracle中与日期时间有关的运算函数
    R
    珍惜现在,感恩生活 多重背包
    Piggy-Bank 完全背包
    骨骼收集器01背包
    D
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/12818827.html
Copyright © 2011-2022 走看看