• 「模板」 FHQ_Treap 区间翻转


    「模板」 FHQ_Treap 区间翻转

    <题目链接>


    没有旋转的 Treap 实现区间操作的功能,很好理解,也很好写,只是速度不算太快。

    对于要翻转的区间,把整棵 Treap(存有区间 ([1,n]) 的信息)Split 成 ([1,l-1])([l,r])([r+1,n]) 三部分,给中间部分的根节点打上标记,再一边下传标记一边 Merge 回来。

    注意 Split 时,要按元素个数,不能按权值,因为元素个数可以通过维护节点信息的 size 域而直接得到,但随着区间的翻转,权值会乱套。

    一定注意先推标记!!先推标记!!先推标记!!

    就因为标记推晚了,我调了一天。

    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    using std::swap;
    const int MAXN=100010;
    int n,m;
    class FHQ_Treap
    {
    	public:
    		FHQ_Treap(void)
    		{
    			rt=cnt=0;
    			memset(a,0,sizeof a);
    		}
    		void Insert(int x)
    		{
    			s[++cnt]=node(x,Random(),1);
    			Merge(rt,rt,cnt);
    		}
    		void Reverse(int x,int y)
    		{
    			int l=0,r=0,t=0;
    			Split(rt,x-1,l,t),Split(t,y-x+1,t,r);
    			s[t].lazy^=1,Merge(l,l,t),Merge(rt,l,r);
    		}
    		void Print(void)
    		{
    			DFS(rt),putchar('
    ');
    		}
    	private:
    		bool a[MAXN];
    		int rt,cnt;
    		struct node
    		{
    			int v,p,size,lazy,c[2];
    			node(int _v=0,int _p=0,int _size=0)
    			{
    				v=_v,p=_p,size=_size,lazy=0;
    				memset(c,0,sizeof c);
    			}
    		}s[MAXN];
    		int Random(void)
    		{
    			int x;
    			while(a[x=rand()%MAXN]);
    			a[x]=1;
    			return x;
    		}
    		void Update(int i)
    		{
    			s[i].size=s[s[i].c[0]].size+s[s[i].c[1]].size+1;
    		}
    		void PushDown(int i)
    		{
    			int &l=s[i].c[0],&r=s[i].c[1];
    			swap(l,r);
    			if(l)
    				s[l].lazy^=1;
    			if(r)
    				s[r].lazy^=1;
    			s[i].lazy=0;
    		}
    		void Split(int i,int x,int &l,int &r)
    		{
    			if(!i)
    			{
    				l=r=0;
    				return;
    			}
    			if(s[i].lazy)
    				PushDown(i);
    			int t=s[s[i].c[0]].size+1;
    			if(x<t)
    				Split(s[r=i].c[0],x,l,s[i].c[0]);
    			else
    				Split(s[l=i].c[1],x-t,s[i].c[1],r);
    			Update(i);
    		}
    		void Merge(int &i,int l,int r)
    		{
    			if(!l || !r)
    			{
    				i=l|r;
    				return;
    			}
    			if(s[l].p>s[r].p)
    			{
    				if(s[l].lazy)
    					PushDown(l);
    				Merge(s[i=l].c[1],s[l].c[1],r);
    			}
    			else
    			{
    				if(s[r].lazy)
    					PushDown(r);
    				Merge(s[i=r].c[0],l,s[r].c[0]);
    			}
    			Update(i);
    		}
    		void DFS(int i)
    		{
    			if(s[i].lazy)
    				PushDown(i);
    			if(s[i].c[0])
    				DFS(s[i].c[0]);
    			printf("%d ",s[i].v);
    			if(s[i].c[1])
    				DFS(s[i].c[1]);
    		}
    }T;
    int main(int argc,char *argv[])
    {
    	srand((unsigned)time(NULL));
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=n;++i)
    		T.Insert(i);
    	for(int i=1,l,r;i<=m;++i)
    	{
    		scanf("%d %d",&l,&r);
    		T.Reverse(l,r);
    	}
    	T.Print();
    	return 0;
    }
    

    谢谢阅读。

  • 相关阅读:
    java String 转Json报错 java.lang.NoClassDefFoundError: org/apache/commons/lang/exception/NestableRuntim
    Idea 进行断点调试的 快捷键
    spring AOP的使用步骤
    AOP的定义和原理
    SpringBoot入门篇--使用IDEA创建一个SpringBoot项目
    详解CI、CD相关概念
    intellij idea 的全局搜索快捷键方法
    面向对象之工厂模式与构造函数模式的区别
    冒泡排序和快速排序
    java里的数组和list分别在什么情况下使用?
  • 原文地址:https://www.cnblogs.com/Capella/p/8506459.html
Copyright © 2020-2023  润新知