【BZOJ3223】文藝平衡樹(Splay)


題面

題目描述

您需要寫一種數據結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:翻轉一個區間,例如原有序序列是5 4 3 2 1,翻轉區間是[2,4]的話,結果是5 2 3 4 1
輸入輸出格式
輸入格式:
第一行為n,m n表示初始序列有n個數,這個序列依次是(1,2,⋯n−1,n),m表示翻轉操作次數。接下來m行每行兩個數 [l,r] 數據保證 1≤l≤r≤n

輸出格式:

輸出一行n個數字,表示原始序列經過m次變換后的結果

輸入樣例

5 3
1 3
1 3
1 4

輸出樣例

4 3 2 1 5

說明

n,m≤100000 n, m \leq 100000 n,m≤100000

題解

這里的Splay維護的顯然不再是權值排序
現在按照的是序列中的編號排序(不過在這道題目里面就是權值誒。。。)
那么,繼續考慮,其實最終的結果也就是整顆Splay的中序遍歷(平衡樹的性質誒)
那么,現在如果按照權值來維護顯然是不正確的
繼續找找規律,發現,如果一個點在序列中的位置為第K個
那么,他就是平衡樹的第K大(就當做普通的Splay來看的話)
所以,序列中的位置就變成了區間的第K大點
繼續考慮如何翻轉
翻轉也就是整顆子樹的每一個節點的左右兒子交換
因此,只要在根節點的地方打一個標記
在旋轉之前下方一下標記就行了
最后輸出的時候輸出的就是Splay的中序遍歷
至於初始的Splay怎么建立,可以直接構造完美的Splay
像我這種比較懶得,直接弄了一個insert。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAX 200000
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
struct Node
{
	int ch[2];
	int ff,v;
	int size;
	int mark;
	void init(int x,int fa)
		{
			ff=ch[0]=ch[1]=0;
			size=1;v=x;ff=fa;
		}
}t[MAX];
int N,root,M,tot;
inline void pushup(int x)
{
	t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
}
inline void pushdown(int x)
{
	if(t[x].mark)
	{
		t[t[x].ch[0]].mark^=1;
		t[t[x].ch[1]].mark^=1;
		t[x].mark=0;
		swap(t[x].ch[0],t[x].ch[1]);
	}
}
inline 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);
}
inline void Splay(int x,int goal)
{
	while(t[x].ff!=goal)
	{
		int y=t[x].ff;int z=t[y].ff;
		if(z!=goal)
			(t[z].ch[1]==y)^(t[y].ch[1]==x)?rotate(x):rotate(y);
		rotate(x);
	}
	if(goal==0)root=x;
}
inline void insert(int x)
{
	int u=root,ff=0;
	while(u)ff=u,u=t[u].ch[x>t[u].v];
	u=++tot;
	if(ff)t[ff].ch[x>t[ff].v]=u;
	t[u].init(x,ff);
	Splay(u,0);
}
inline int Kth(int k)
{
	int u=root;
	while(233)
	{
		pushdown(u);
		if(t[t[u].ch[0]].size>=k)u=t[u].ch[0];
		else if(t[t[u].ch[0]].size+1==k)return u;
		else k-=t[t[u].ch[0]].size+1,u=t[u].ch[1];
	}
}
void write(int u)
{
	pushdown(u);
	if(t[u].ch[0])write(t[u].ch[0]);
	if(t[u].v>1&&t[u].v<N+2)printf("%d ",t[u].v-1);
	if(t[u].ch[1])write(t[u].ch[1]);
}
inline void Work(int l,int r)
{
	l=Kth(l);
	r=Kth(r+2);
	Splay(l,0);
	Splay(r,l);
	t[t[t[root].ch[1]].ch[0]].mark^=1;
}
int main()
{
	N=read();M=read();
	for(int i=1;i<=N+2;++i)insert(i);
	while(M--)
	{
		int l=read(),r=read();
		Work(l,r);
	}
	write(root);
	printf("\n");
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM