[ZJOI2007]报表统计,洛谷P2042,splay

正题

      报表统计一点都不好玩

      最烦的就是有一个Min_Gap和一个Min_Sort_Gap。

      我们想怎么维护。

      用一个left来表示这个子树最左边的值,用right来表示这段去见最右边的值。

      那么与一个节点,我们就可以快速地知道他的前驱和后继是谁(左儿子的right和右儿子的left)。

      继续向上维护left和right即可。

      第二个操作相当于排完序的,所以建两棵伸展树维护排名或权值即可得知。

// luogu-judger-enable-o2
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

int n,m;
int a[500010];
struct node{
	int num,son[2],f,t,more,mmin,left,right;
}s1[5000010],s2[5000010];
int image[500010];
int tot=0;
int root1=0,root2=0;
bool tf=false;

void update(int x,node* s){
	if(x==0) return ;
	s[x].t=s[s[x].son[0]].t+s[s[x].son[1]].t+1;
	s[x].left=s[x].right=s[x].num;
	s[x].mmin=1e9;
	if(s[x].son[0]!=0) s[x].left=s[s[x].son[0]].left;
	if(s[x].son[1]!=0) s[x].right=s[s[x].son[1]].right;
	s[x].mmin=min(s[s[x].son[0]].mmin,s[s[x].son[1]].mmin);
	s[x].mmin=min(s[x].mmin,min(abs(s[x].num-s[s[x].son[0]].right),abs(s[x].num-s[s[x].son[1]].left)));
}

void rotate(int x,int w,node* s){
	int f=s[x].f,ff=s[f].f;
	s[f].son[1-w]=s[x].son[w];
	if(s[x].son[w]!=0) s[s[x].son[w]].f=f;
	if(s[ff].son[1]==f) s[ff].son[1]=x;
	else s[ff].son[0]=x;
	s[x].f=ff;
	s[x].son[w]=f;
	s[f].f=x;
	update(f,s);
	update(x,s);
}

void splay(int x,int tar,node* s){
	while(s[x].f!=tar){
		int f=s[x].f,ff=s[f].f;
		if(ff==tar) {
			if(s[f].son[0]==x) rotate(x,1,s);
			else rotate(x,0,s);
		}
		else{
			if(s[ff].son[0]==f){
				if(s[f].son[0]==x) {rotate(f,1,s);rotate(x,1,s);}
				else {rotate(x,0,s);rotate(x,1,s);}
			}
			else{
				if(s[f].son[0]==x) {rotate(x,1,s);rotate(x,0,s);}
				else {rotate(f,0,s);rotate(x,0,s);}
			}
		}
	}
}

void build(int x,int y,node* s){
	tot++;
	int i=tot;
	int mid=(x+y)/2;
	s[i].son[0]=s[i].son[1]=0;
	s[i].num=a[mid];
	if(!tf)image[mid]=i;
	if(x<mid){
		s[i].son[0]=tot+1;
		s[tot+1].f=i;
		build(x,mid-1,s);
	}
	if(mid<y){
		s[i].son[1]=tot+1;
		s[tot+1].f=i;
		build(mid+1,y,s);
	}
	update(i,s);
}

void insert1(int x,int t){
	int op=s1[x].more;
	s1[x].more++;
	splay(x,0,s1);
	root1=x;
	int now=s1[x].son[1];
	if(op==0) now=x;
	while(op!=0){
		if(op<=s1[s1[now].son[0]].t) now=s1[now].son[0];
		else if(op>s1[s1[now].son[0]].t+1) op=op-s1[s1[now].son[0]].t-1,now=s1[now].son[1];
		else break;  
	}
	splay(now,0,s1);
	root1=now;
	int pos=s1[now].son[1];
	while(s1[pos].son[0]!=0 && pos!=0) pos=s1[pos].son[0];
	if(pos!=0)splay(pos,now,s1);
	tot++;
	s1[tot].num=t;
	s1[now].son[1]=tot;s1[tot].f=now;
	s1[pos].f=tot;s1[tot].son[1]=pos;
	update(pos,s1);
	update(tot,s1);
	update(now,s1);
}

void insert2(int t){
	int now=root2;
	while(s2[now].num!=t){
		if(t<s2[now].num){
			if(s2[now].son[0]==0) break;
			else now=s2[now].son[0];
		}
		else{
			if(s2[now].son[1]==0) break;
			else now=s2[now].son[1];
		}
		
	}
	splay(now,0,s2);
	root2=now;
	if(s2[now].num<t){
		int pos=s2[now].son[1];
		while(s2[pos].son[0]!=0 && pos!=0)pos=s2[pos].son[0];
		if(pos!=0) splay(pos,now,s2);
		tot++;
		s2[tot].num=t;
		s2[now].son[1]=tot;s2[tot].f=now;
		s2[pos].f=tot;s2[tot].son[1]=pos;
		update(pos,s2);
		update(tot,s2);
		update(now,s2);
	}
	else{
		int pos=s2[now].son[0];
		while(s2[pos].son[1]!=0) pos=s2[pos].son[1];
		if(pos!=0) splay(pos,now,s2);
		tot++;
		s2[tot].num=t;
		s2[now].son[0]=tot;s2[tot].f=now;
		s2[pos].f=tot;s2[tot].son[0]=pos;
		update(pos,s2);
		update(tot,s2);
		update(now,s2);
	}
}

int main(){
	s1[0].mmin=s2[0].mmin=1e9;
	s1[0].num=s2[0].num=-1e9;
	s1[0].left=s2[0].left=s1[0].right=s2[0].right=-1e9;
	s2[0].son[0]=s2[0].son[1]=0;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	root1=root2=1;
	build(1,n,s1);
	sort(a+1,a+1+n);
	tf=true;tot=0;
	build(1,n,s2);
	char c[20];
	int x,y;
	for(int i=1;i<=m;i++){
		scanf("%s",c);
		if(c[0]=='I') {	
			scanf("%d %d",&x,&y);
			insert1(image[x],y);
			tot--;
			insert2(y);
		}
		else if(c[4]=='G') printf("%d\n",s1[root1].mmin);
		else if(c[4]=='S') printf("%d\n",s2[root2].mmin);
	}
}

阅读更多
版权声明: https://blog.csdn.net/Deep_Kevin/article/details/80321729
个人分类: splay
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭