Splay 记录

luogu 模板 P3391 【模板】文艺平衡树(Splay)。

知识点:1.splay模板题,练习splay,rotate顺序:x变成z的儿子,x的一个儿子变为y的一个儿子(具体哪个看代码),y变为x的儿子。

    2.splay函数:如起码还需转两次,如最近两次旋转路径为直线,则先转x的父亲,再转x;如为折线,转两次x。

    3.insert函数:记得记录父亲节点,如果父亲存在还要让父亲连向被插入数x,记得新建节点,新建节点两个儿子设置为0,将siz数设为1。

#include <bits/stdc++.h>
using namespace std;
int n,m;
int cnt = 0;
struct edge
{
	int ch[2];
	int ff;
	int siz;
	int val;
	int lazy;
}t[200002];
int rt = 0;
void pushup(int x)
{
	//错误1:忘记加1(这个点本身),原为t[x].siz = t[t[x].ch[0]].siz + t[t[x].ch[1]].siz; 
	t[x].siz = t[t[x].ch[0]].siz + t[t[x].ch[1]].siz + 1;
}
void pushdown(int x)
{
    if(t[x].lazy)
    {
        t[t[x].ch[0]].lazy^=1;
        t[t[x].ch[1]].lazy^=1;
        t[x].lazy=0;
        swap(t[x].ch[0],t[x].ch[1]);
    }
}
void rotate(int x)
{
	int y = t[x].ff;
    int z = t[y].ff;
    int k = t[y].ch[1] == x;
    t[z].ch[t[z].ch[1] == y] = x;
    t[x].ff = z;
    t[y].ch[k] = t[x].ch[k^1];
    t[t[x].ch[k^1]].ff = y;
    t[x].ch[k^1] = y;
    t[y].ff = x;
    pushup(y);
    pushup(x);
}
void splay(int x,int goal)
{
	while(t[x].ff != goal)
	{
		int y = t[x].ff,z = t[y].ff;
	    if(z != goal)
	    	if((t[z].ch[1] == y)^(t[y].ch[1] == x))rotate(x);
	     	else rotate(y);
	     rotate(x);
	}
	if(goal == 0)rt = x;
}
void insert(int x)
{
	int u = rt,ff = 0;
	while(u)
	{
		ff = u;
		u = t[u].ch[t[u].val < x];
	}
    u = ++cnt;
    if(ff)t[ff].ch[t[ff].val < x] = u;
    t[u].val = x;
    t[u].siz = 1;
    t[u].ff = ff;
    t[u].ch[0] = t[u].ch[1] = 0;
    splay(u,0);
}
int Kth(int k)
{
	int u = rt;
	while(1)
	{
		//错误2:一开始把所有t[t[u].ch[0]].siz写成了t[u].siz,理解错误。 
		pushdown(u); 
		if(t[t[u].ch[0]].siz >= k)u = t[u].ch[0];
		else if(t[t[u].ch[0]].siz + 1 == k)return u;
		else k -= (t[t[u].ch[0]].siz + 1),u = t[u].ch[1];
	}
	
}

void work(int l,int r)
{
	int ls = Kth(l);
	int rs = Kth(r + 2);
	splay(ls,0);
	splay(rs,ls);
	t[t[t[rt].ch[1]].ch[0]].lazy ^= 1;
}
void print(int u)
{
    pushdown(u);
    if(t[u].ch[0])print(t[u].ch[0]);
    if(t[u].val>1&&t[u].val<n+2)printf("%d ",t[u].val-1);
    if(t[u].ch[1])print(t[u].ch[1]);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n + 2;i++)insert(i);//这里是因为要留出两个空节点,一头一尾,给1当前驱,给n当后继,而1变成2,2变成3.....n变成n + 1。 
	int l,r;
    while(m--)
    {
    	scanf("%d%d",&l,&r);
    	work(l,r);
    }
    print(rt);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xyj1/p/10416264.html