天天看點

splay BZOJ1500 NOI2005 維護數列

傳說中的splay神題,其實個人感覺還行,算是上個時代的資料結構神題吧,現在都流行各種分治,各種神轉化+樸素線段樹,或者動态XXX函數式XXX

做法個人感覺已經說爛了,論文中說的很細

每個節點維護size,father,child【2】(兩個孩子)

标記要維護的是same,SameVal,res,MaxL,MaxR,MaxM,sum

分别是是否修改為一樣的值,修改的值,是否翻轉,這個區間從左邊開始的最大連續值,從右邊開始的最大值,整個區間的最長子序列,還有這個序列的和

然後就是維護了 

注意down(向下傳标記)的時候先傳same再傳res

如果有same的話就不用傳res了,這個不難了解吧

剩下的個人感覺沒什麼說的必要了

都是splay維護區間問題的經典問題

如果沒寫過splay維護區間問題的話

想入門看這裡

哦對有個小插曲,個人的代碼在bzoj挂了。。。原因不知道。。。

但是代碼在BSOJ上AC了,時間是3s多一點

我自己問bzoj管理者要的資料本地的測試中也過了

個人感覺代碼應該沒問題

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MAX 2850003
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define inf 0x7fffffff/4

using namespace std;

int pos,total,tot=0,root;
int size[MAX],child[2][MAX],res[MAX];
int same[MAX],value[MAX],a[MAX],b[MAX],sum[MAX];
int MaxL[MAX],MaxR[MAX],MaxM[MAX],father[MAX],SameVal[MAX];

void down(int x)
{
	if(!x)
		return;
	if(same[x])
	{
		same[x]=res[x]=0;

		value[x]=SameVal[x];
		sum[x]=SameVal[x]*size[x];

		if(value[x]<0)
			MaxL[x]=MaxR[x]=MaxM[x]=value[x];
		else
			MaxL[x]=MaxR[x]=MaxM[x]=sum[x];

		same[child[0][x]]=same[child[1][x]]=1;
		SameVal[child[0][x]]=SameVal[child[1][x]]=SameVal[x];
	}
	if(res[x])
	{
		/*if(child[0][x])
			res[child[0][x]]^=1;
		if(child[1][x])
			res[child[1][x]]^=1;
		swap(MaxL[child[0][x]],MaxR[child[1][x]]);
		swap(child[0][x],child[1][x]);
		res[x]=0;*/
		res[x]=0;
		swap(child[0][x],child[1][x]);
		swap(MaxL[x],MaxR[x]);

		res[child[0][x]]=!res[child[0][x]];
		res[child[1][x]]=!res[child[1][x]];
	}
}

void up(int x)
{
	if(!x)
		return;
	down(child[0][x]);
	down(child[1][x]);

	size[x]=1+size[child[0][x]]+size[child[1][x]];
	sum[x]=sum[child[0][x]]+value[x]+sum[child[1][x]];

	//l
	MaxL[x]=MaxL[child[0][x]];
	MaxL[x]=max(MaxL[x],max(sum[child[0][x]]+value[x],sum[child[0][x]]+value[x]+MaxL[child[1][x]]));

	//r
	MaxR[x]=MaxR[child[1][x]];
	MaxR[x]=max(MaxR[x],max(sum[child[1][x]]+value[x],sum[child[1][x]]+value[x]+MaxR[child[0][x]]));

	//m
	MaxM[x]=max(value[x],MaxR[child[0][x]]+value[x]+MaxL[child[1][x]]);
	MaxM[x]=max(MaxM[x],max(MaxM[child[0][x]],MaxM[child[1][x]]));
	MaxM[x]=max(MaxM[x],max(value[x]+MaxR[child[0][x]],value[x]+MaxL[child[1][x]]));
	MaxM[x]=max(MaxM[x],MaxL[child[1][x]]+value[x]+MaxR[child[0][x]]);
	return;
}

void build(int &x,int l,int r)
{
	if(l>r)
	{
		x=0;
		return;
	}
	x=++tot;
	int mid=(l+r)>>1;
	value[x]=sum[x]=a[mid];
	same[x]=0;
	res[x]=0;
	MaxL[x]=MaxR[x]=MaxM[x]=SameVal[x]=-inf;
	build(child[0][x],l,mid-1);
	build(child[1][x],mid+1,r);
	if(child[0][x])
		father[child[0][x]]=x;
	if(child[1][x])
		father[child[1][x]]=x;
	up(x);
	return ;
}

void Insert(int &x,int l,int r)
{
	if(l>r)
	{
		x=0;
		return;
	}
	int mid=(l+r)>>1;
	x=++tot;
	value[x]=sum[x]=b[mid];
	same[x]=res[x]=0;
	MaxL[x]=MaxR[x]=MaxM[x]=SameVal[x]=-inf;
	Insert(child[0][x],l,mid-1);
	Insert(child[1][x],mid+1,r);
	if(child[0][x])
		father[child[0][x]]=x;
	if(child[1][x])
		father[child[1][x]]=x;
	up(x);
}

int select(int k)
{
	int t=root;
	while(1)
	{
		down(t);
	//	printf("fuck\n");
		if(size[child[0][t]]+1==k)
			return t;
		if(size[child[0][t]]>=k)
			t=child[0][t];
		else
			k-=size[child[0][t]]+1,t=child[1][t];
	}
	return -1;
}

void rotate(int p)
{
	int q=father[p],y=father[q],x=(child[1][q]==p);
	down(q);
	down(p);
	down(child[0][p]),down(child[1][p]),down(child[x^1][p]);

	father[child[x][q]=child[x^1][p]]=q;
	father[child[x^1][p]=q]=p;
	father[p]=y;
	if(y)
		child[child[1][y]==q][y]=p;

	up(q);
	return;
}	

void splay(int x,int aim=0)
{
	down(x);
	for(int y;(y=father[x])!=aim;rotate(x))
		if(father[y]!=aim)
		{
			if((child[0][y]==y)==(child[0][y]==x))
				rotate(y);
			else
				rotate(x);
		}//*/
	/*for(int y;(y=father[x])!=aim;)
	{
		int z;
		if((z=father[y])==aim)
			rotate(x);
		else
			if((child[1][y]==x)==(child[1][z]==y))
				rotate(y),rotate(x);
			else
				rotate(x),rotate(x);
	}*/
	if(!aim)
		root=x;
	up(x);
	return;
}

void debug()
{
	printf("--------------------debug------------------------\n");
	rep(i,1,tot)
		printf("%d %d %d\n",i,select(i),value[select(i)]);
	printf("i fa child_l   child_r size MaxL MaxR MaxM       val   sum   res same SameVal\n");
	rep(i,1,tot)
		printf("%d %d   %d          %d     %d  %d %d %d            %d     %d  %d %d %d\n",i,father[i],child[0][i],child[1][i],size[i],MaxL[i],MaxR[i],MaxM[i],value[i],sum[i],res[i],same[i],SameVal[i]);
	printf("--------------------debug------------------------\n");
}

void insert()
{
	splay(select(pos+1));
	splay(select(pos+2),root);
	Insert(child[0][child[1][root]],1,total);
	if(child[0][child[1][root]])
		father[child[0][child[1][root]]]=child[1][root];
	up(child[1][root]);
	up(root);
	return ;
}

void Delete()
{
	splay(select(pos));
	splay(select(pos+total+1),root);
//	debug();
	child[0][child[1][root]]=0;
	splay(child[1][root]);
//	up(child[1][root]);
//	up(root);
//	tot-=total;
	return;
}

void make_same(int Pos,int Total,int ind)
{
	splay(select(Pos));
	splay(select(Pos+Total+1),root);

	same[child[0][child[1][root]]]=1;
	SameVal[child[0][child[1][root]]]=ind;

	splay(child[0][child[1][root]],0);
//	down(child[0][child[1][root]]);
//	up(child[1][root]);
//	up(root);
	return;
}

void reserve()
{
	splay(select(pos));
	splay(select(pos+total+1),root);
	res[child[0][child[1][root]]]^=1;
	
	splay(child[0][child[1][root]],0);
}

int ask_num()
{
	//printf("ask %d %d %d %d\n",pos,total,select(pos),select(pos+1+total));
	splay(select(pos));
	splay(select(pos+1+total),root);
	down(child[0][child[1][root]]);
	return sum[child[0][child[1][root]]];
}

int get_max_num()
{
	down(root);
	up(root);
	return MaxM[root];
}

void get(int &x)
{
	int ret=0;
	char ch;
	while(ch=getchar())
		if((ch>='0'&&ch<='9')||ch=='-')
			break;
	bool f=(ch=='-');
	if(f)
		ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar())
		ret=ret*10+ch-'0';
	x=f?-ret:ret;
	return;
}

int main()
{
	MaxL[0]=MaxR[0]=MaxM[0]=-inf;
	int n,m;
	scanf("%d%d",&n,&m);
	a[1]=a[n+2]=-inf;
	rep(i,2,n+1)
		scanf("%d",&a[i]);
	n+=2;
	build(root,1,n);
	while(m--)
	{
		char s[300];
		scanf("%s",s);
		switch (s[0])
		{
			case 'I':
				get(pos);
				get(total);
				rep(i,1,total)
					get(b[i]);
				insert();
				break;
			case 'D':
				get(pos);
				get(total);
				Delete();
				break;
			case 'M':
				{
				if(s[2]=='K')
				{
					int c;
					get(pos),get(total),get(c);
					make_same(pos,total,c);
					break;
				}
				else
				{
					printf("%d\n",get_max_num());
					break;
				}
				break;
				}
			case 'R':
				get(pos),get(total);
				reserve();
				break;
			case 'G':
				get(pos),get(total);
				printf("%d\n",ask_num());
				break;
		}
		//debug();
	}
	return 0;
}
           

哦還附帶贈送資料生成器

自己可以調資料生成的大小,我這個隻有10個數,不過過幾百組資料的話應該就沒問題了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#define mod 10
#define del 10

using namespace std;

int main()
{
	freopen("1500.in","w",stdout);
	srand((unsigned)time(0));
	int n=10,m=6,no;

	string s[10];
	s[1]="INSERT";s[2]="DELETE";
	s[3]="MAKE-SAME";s[4]="RESERVE";
	s[5]="GET-SUM";s[6]="MAX-SUM";
	printf("%d %d\n",n,m);
	for(int i=1;i<=n;i++)
		no=rand()%mod-del,printf("%d\n",no);
	while(m--)
	{
		int con=rand()%6+1;
		if(con==1)
		{
			cout<<s[1]<<' ';
			int a=n,b=n;
			while(a+b>n)
				a=rand()%n+1,b=rand()%n+1;
			printf("%d %d",a,b);
			int now;
			while(b--)
				now=rand()%mod-del,printf(" %d");
			printf("\n");
		}
		else
			if(con==2||con==4||con==5)
			{
				cout<<s[con]<<' ';
				int a=n,b=n;
				while(a+b>n)
					a=rand()%n+1,b=rand()%n+1;
				printf("%d %d\n",a,b);
			}
			else
				if(con==3)
				{
					cout<<s[3]<<' ';
					int a=n,b=n;
					while(a+b>n)
						a=rand()%n+1,b=rand()%n+1;
					int now=rand()%mod-del;
					printf("%d %d %d\n",a,b,now);
				}
				else
					if(con==6)
						cout<<s[6]<<"\n";
	}
	return 0;
}
           

繼續閱讀