Splay维护序列 & 洛谷 P3391 【模板】文艺平衡树

传送门


解题思路

Splay如何维护序列呢?
以序列下标作为val值,扔到Splay中。
因为有区间翻转操作,所以实际上并不能保证绝对的按照val值排序,也就是说Splay的中序遍历结果是真正的序列,而val值对应的是当前序列的每个元素原来的位置。

与普通的Splay的区别在于多了一个区间翻转操作,可以把当前第l-1个元素旋转到根,第r+1个元素旋转到根的右儿子,这样l~r的元素就是以根的右儿子的左儿子为根的子树了,打个lazy tag即可。记得各个操作到达某个节点是先pushdown一下。

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
using namespace std;
template<class T>inline void read(T &x)
{
    x=0; char c=getchar(); bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
const int maxn=100005;
int n,m,cnt,lazy[maxn],rt;
struct node{
	int fa,val,son[2],siz;
}tr[maxn];
int New(int val,int fa){
	cnt++;
	tr[cnt].val=val;
	tr[cnt].fa=fa;
	tr[cnt].son[0]=tr[cnt].son[1]=0;
	tr[cnt].siz=1;
	return cnt;
}
void update(int x){
	if(!x) return;
	tr[x].siz=1;
	if(tr[x].son[0]) tr[x].siz+=tr[tr[x].son[0]].siz;
	if(tr[x].son[1]) tr[x].siz+=tr[tr[x].son[1]].siz;
}
void pushdown(int x){
	if(lazy[x]){
		if(tr[x].son[0]) lazy[tr[x].son[0]]^=1;
		if(tr[x].son[1]) lazy[tr[x].son[1]]^=1;
		swap(tr[x].son[0],tr[x].son[1]);
		lazy[x]=0;
	}
}
void rotate(int x){
	int y=tr[x].fa,z=tr[y].fa;
	pushdown(y);pushdown(x);
	int c=(tr[y].son[1]==x);
	tr[x].fa=z;
	tr[y].fa=x;
	if(tr[x].son[!c]) tr[tr[x].son[!c]].fa=y;
	tr[y].son[c]=tr[x].son[!c];
	tr[x].son[!c]=y;
	if(z) tr[z].son[tr[z].son[1]==y]=x;
	update(y);
	update(x);
}
void splay(int x,int goal){
	if(x==goal) return;
	while(tr[x].fa!=goal){
		int y=tr[x].fa,z=tr[y].fa;
		if(z!=goal) ((tr[y].son[1]==x)^(tr[z].son[1]==y))?rotate(x):rotate(y);
		rotate(x);
	}
	if(!goal) rt=x;
}
void insert(int val){
	if(!rt){
		rt=New(val,0);
		return;
	}
	int x=rt;
	while(1){
		pushdown(x);
		if(tr[x].son[tr[x].val<val]) x=tr[x].son[tr[x].val<val];
		else{
			tr[x].son[tr[x].val<val]=New(val,x);
			update(x);
			splay(cnt,0);
			return;
		}
	}
}

int find(int tot){
	int x=rt;
	while(1){
		pushdown(x);
		if(tot>1+(tr[x].son[0]?tr[tr[x].son[0]].siz:0)) tot-=1+(tr[x].son[0]?tr[tr[x].son[0]].siz:0),x=tr[x].son[1];
		else if(!tr[x].son[0]||tot==1+(tr[x].son[0]?tr[tr[x].son[0]].siz:0)) return x;
		else x=tr[x].son[0];
	}
}
void Reverse(int l,int r){
	l=find(l),r=find(r+2);
	splay(l,0);
	splay(r,rt);
	lazy[tr[tr[rt].son[1]].son[0]]^=1;
}
int getval(int x){
	return tr[find(x)].val;
}
int main(){
	read(n);read(m);
	for(int i=0;i<=n+1;i++) insert(i);
	for(int i=1;i<=m;i++){
		int l,r;
		read(l);read(r);
		if(l==r) continue;
		Reverse(l,r);
	}
	for(int i=1;i<=n;i++) print(getval(i+1)),putchar(' ');
	return 0;
}
上一篇:洛谷 P1503 鬼子进村(平衡树)


下一篇:【数据采集与融合】第四次实验