zoukankan      html  css  js  c++  java
  • P3391 【模板】文艺平衡树(Splay)

    Splay

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    struct node *nil;//防止真的访问了NULL导致re(从零开始的编码生活)
    struct node
    {
    	int val;//节点值
    	int size;//以他为根的节点的子树节点个数(包括他自己)
    	int flag;//懒标记
    	node *ch[2];//左右儿子
    	void sum()//重新计算size
    	{
    		size=1+ch[0]->size+ch[1]->size;//因为这里我们定义了不会re的无意义空地址。所以就不用判断
    	}
    	int cmp(int kth)//比较该往那颗子树上走
    	{
    		int s=ch[0]->size;
    		if(kth==s+1)//就是当前根
    			return -1;
    		return (kth <= s ? 0 : 1);
    	}
    }*root;
    int n,m;
    void init()//初始化
    {
    	nil=new node;
    	nil->flag=0;
    	nil->size=0;
    	nil->val=0;
    	nil->ch[0]=nil->ch[1]=nil;
    	root=nil;
    }
    node *New()//申请内存并初始化
    {
    	node *res=new node;
    	res->size=1;
    	res->flag=0;
    	res->ch[0]=res->ch[1]=nil;
    	return res;
    }
    void rotato(node* &now,int base)//旋转函数。应为这里是引用指针。所以直接指向就可以了。不用顾忌其他东西辣( ̄▽ ̄)~*
    {
    	node *k=now->ch[base^1];//利用异或进行取反
    	now->ch[base^1]=k->ch[base];
    	k->ch[base]=now;
    	now->sum();//先计算被旋转下去的根,再计算新的根
    	k->sum();
    	now=k;
    }
    void build(node* &now,int l,int r)//建树,一定要引用。l为左边界。
    {
    	if(l>r)
    		return ;
    	int mid=(l+r)>>1;
    	if(now==nil)//如果为空就动态申请,当然也可以动态删除
    	{
    		now=New();
    		now->val=mid;
    	}
    	build(now->ch[0],l,mid-1);//左右递归的建树
    	build(now->ch[1],mid+1,r);
    	now->sum();
    	return ;
    }
    void push_down(node* &now)//下放lazy tag
    {
    	if(now!=nil&&now->flag)
    	{
    		swap(now->ch[0],now->ch[1]);
    		now->ch[0]->flag^=1;
    		now->ch[1]->flag^=1;
    		now->flag=0;
    	}
    	return ;
    }
    void visit(node* &now)//中序便利
    {
    	if(now==nil)
    		return ;
    	push_down(now);
    	visit(now->ch[0]);
    	if(now->val!=0&&now->val!=n+1)
    		printf("%d ",now->val);
    	visit(now->ch[1]);
    }
    void splaykth(node* &now,int kth)//将以now为根的树中把第kth小的旋转到根上
    {
    	push_down(now);
    	int d=now->cmp(kth);
    	if(d!=-1)
    	{
    		push_down(now->ch[d]);
    		if(d==1)
    			kth-=now->ch[0]->size+1;//换根要重新计算kth,下同
    		int d2=now->ch[d]->cmp(kth);
    		if(d2!=-1)
    		{
    			if(d2==1)
    				kth-=now->ch[d]->ch[0]->size+1;
    			splaykth(now->ch[d]->ch[d2],kth);
    			if(d==d2)
    				rotato(now,d2^1),rotato(now,d^1);//一字型
    			else
    				rotato(now->ch[d],d2^1),rotato(now,d^1);//之字形
    		}
    		else
    			rotato(now,d^1);//单旋
    	}
    }//其实这里应该要判空的,以防止非法情况出现。不过根据这个题。我们调用的时候没有非法情况
    void Reverse(int l,int r)//翻转,这里因为有可能涉及到将1~n都翻转一遍。所以我们可以建两个哨兵节点,位置在0,n+1上。
    {       //将l~r翻转
            //l,r为第l个数到第r个数(1~n中)
    	splaykth(root,l);//把l-1翻上来
    	splaykth(root->ch[1],r+1-root->ch[0]->size);//把r+1翻到右子树根的位置上。这样根节点右儿子的左子树上就是l~r。
    	root->ch[1]->ch[0]->flag^=1;//打上懒标记
    	return ;
    }
    int main()
    {
    	init();
    	scanf("%d%d",&n,&m);
    	build(root,0,n+1);
    	int a,b;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&a,&b);
    		Reverse(a,b);
    	}
    	/*splaykth(root,7);
    	cout<<root->val;*/
    	visit(root);//中序遍历一波
    }
    
  • 相关阅读:
    .NET 用 Unity 依赖注入——概述注册和解析类型(1)
    .NET 服务器定位模式(Service Locator Pattern)——Common Service Locator
    用什么样的语言就有什么样的公司【转载】
    编程语言和工具比较【翻译】
    .NET 基于任务的异步模式(Task-based Asynchronous Pattern,TAP) async await
    RocketMQ【未完成】
    Dapper
    Java 控制反转和依赖注入模式【翻译】【整理】
    Java 面向切面编程(Aspect Oriented Programming,AOP)
    Groovy 与 Python 的差异【翻译】
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9047440.html
Copyright © 2011-2022 走看看