ZC的序列

题目链接

题目大意

给一个长度为\(n\)的数列,\(m\)次操作或询问。

每次操作把\([l,r]\)平移\(x\)个单位,每次询问输出\([l,r]\)

代码及解析

蒟蒻\(TRW\)经过大佬们的愤怒吊锤精心指教之后——

才一个字母一个字母地敲出了这choulou的代码。

这显然是一道平衡树题,可以用\(splay\)维护。

为了方便,我们统一规定向右移动,向左移\(x\iff\)向右移\(-x\)

每次把\([l,r]\)切下,再插入到第\(l+x-1\)个和第\(l+x\)数之间。

注意,是切下之后的数列的第\(l+x-1\)个和第\(l+x\)数之间。

上代码!

//program from TRW
//splay版本 
#include<bits/stdc++.h>
#define b(i) son[i][0]
#define g(i) son[i][1]
#define mid ((l+r)>>1)
#define sex(i) (g(fa[i])==i)
#define up(i) size[i]=size[b(i)]+size[g(i)]+1
using namespace std;
const int nn=101015;
int n,m,opt,l,r,dir,x,a,rt,tot,val[nn];
int fa[nn],size[nn],son[nn][2];
int find(int p,int i){
	int st=size[b(p)]+1;
	if(i<st)return find(b(p),i);
	if(i==st)return p;
	return find(g(p),i-st);
}void zg(int p){
	int f=fa[p],gf=fa[f];
	bool sp=sex(p),sf=sex(f);
	int s=son[p][!sp];
	fa[f]=p,son[p][!sp]=f;
	fa[p]=gf,son[gf][sf]=p;
	fa[s]=f,son[f][sp]=s;
	up(f),up(p); 
}void splay(int a,int b){
	int sf=fa[b];
	for(;fa[a]!=sf;zg(a))
		if(fa[fa[a]]!=sf)
			zg(fa[a]);
	if(!fa[a])rt=a;
}void plant(int&p,int l,int r){
	if(l>r)return ;
	p=++tot;
	plant(b(p),l,mid-1);
	if(mid&&mid<=n)scanf("%d",val+p);
	plant(g(p),mid+1,r);
	fa[b(p)]=fa[g(p)]=p,up(p);
}void print(int p){
	if(!p)return ;
	print(b(p));
	if(val[p]!=0)printf("%d ",val[p]);
	print(g(p));
}int main(){
	scanf("%d%d",&n,&m);
	for(plant(rt,0,n+1);m--;){
		scanf("%d%d%d",&opt,&l,&r);
		splay(find(rt,l),rt);
		splay(find(rt,r+2),g(rt));
		if(opt)print(b(g(rt))),putchar('\n');
		else{
			a=b(g(rt)),b(g(rt))=0;
			up(g(rt)),up(rt);
			scanf("%d%d",&dir,&x);
			if(!dir)x=-x;
			splay(find(rt,l+x),rt);
			splay(find(rt,l+x+1),g(rt));
			fa[b(g(rt))=a]=g(rt);
			up(g(rt)),up(rt);
		}
	}return 0;
}
//program from TRW
//fhq_treap版本 
#include<bits/stdc++.h>
#define up(i) size[i]=size[b(i)]+size[g(i)]+1
#define b(i) son[i][0]
#define g(i) son[i][1]
#define pii pair<int,int>
#define mp make_pair
#define fir first
#define sec second
using namespace std;
const int nn=101015;
int n,m,opt,l,r,dir,x,rt,tot,t1,t2,t3;
int val[nn],rd[nn],size[nn],son[nn][2];
pii f;
void plant(int&p,int l,int r){
	if(l>r)return ;
	int mid=((l+r)>>1);
	rd[p=++tot]=rand();
	plant(b(p),l,mid-1);
	if(mid&&mid<=n)scanf("%d",val+p);
	plant(g(p),mid+1,r),up(p);
}pii cut(int p,int i){
	if(!i)return mp(0,p);
	pii ans;
	int st=size[b(p)]+1;
	if(i<st){
		ans=cut(b(p),i);
		b(p)=ans.second,up(p);
		return mp(ans.first,p);
	}else{
		ans=cut(g(p),i-st);
		g(p)=ans.first,up(p);
		return mp(p,ans.second);
	}
}int merge(int x,int y){
	if(!x||!y)return x|y;
	if(rd[x]<rd[y])return g(x)=merge(g(x),y),up(x),x;
	return b(y)=merge(x,b(y)),up(y),y;
}void print(int p){
	if(!p)return ;
	print(b(p));
	printf("%d ",val[p]);
	print(g(p));
}int main(){
	srand(time(0));
	scanf("%d%d",&n,&m),plant(rt,0,n+1);
	while(m--){
		scanf("%d%d%d",&opt,&l,&r);
		f=cut(rt,l),t1=f.fir,t2=f.sec;
		f=cut(t2,r-l+1),t2=f.fir,t3=f.sec;
		if(opt)print(t2),putchar('\n');
		else{
			scanf("%d%d",&dir,&x);
			if(!dir)x=-x;
			f=cut(merge(t1,t3),l+x);
			t1=f.fir,t3=f.sec;
		}rt=merge(merge(t1,t2),t3);
	}return 0;
}
posted @ 2020-10-15 21:11  ANY_HOW  阅读(401)  评论(0编辑  收藏  举报