【bzoj1500】[NOI2005]维修数列 Splay

终于打败大boss了,耗时一下午。

应该是splay维护序列题型的巅峰了吧。

这道题不能单纯的开点,因为会MLE,所以要用回收节点的过程。

说一下搞法吧:

1、插入,提取区间,递归建树

2、删除,提取区间,把删去的点用一个栈储存下来

3、修改,提取区间,打个标记

4、翻转,提取区间,打个标记

5、求和、最大连续子段和,维护一下就可以了。

WA点:

这道题不用开longlong,简直是福利

没说数据范围,需要回收内存

标记稍微处理一下就可以了没什么

初始化节点注意把权值赋成-inf,虽然好像没用什么用


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define inf 1010000000
#define maxn 510010 

using namespace std;

int fa[maxn],ch[maxn][2],w[maxn],size[maxn],sum[maxn],lmax[maxn],rmax[maxn],ans[maxn];
bool rev[maxn];
bool tag[maxn];
int a[maxn];
int st[maxn];
char s[20];
int n,m,T,tot,root,top;

int newnode()
{
	int num;
	if (top) num=st[top--]; else num=++tot;
	ch[num][0]=ch[num][1]=fa[num]=0;
	tag[num]=rev[num]=0;
	size[num]=1;
	sum[num]=w[num]=rmax[num]=lmax[num]=-inf;
	return num;
}

void update(int x)
{
	if (!x) return;
	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+w[x];
	lmax[x]=max(lmax[ch[x][0]],sum[ch[x][0]]+w[x]+max(0,lmax[ch[x][1]]));
	rmax[x]=max(rmax[ch[x][1]],sum[ch[x][1]]+w[x]+max(0,rmax[ch[x][0]]));
	ans[x]=max(max(ans[ch[x][0]],ans[ch[x][1]]),max(0,rmax[ch[x][0]])+w[x]+max(0,lmax[ch[x][1]]));
}

void reverse(int x)
{
	if (!x) return;
	swap(lmax[x],rmax[x]);
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}

void replace(int x,int d)
{
	if (!x) return;
	w[x]=d;sum[x]=d*size[x];
	lmax[x]=rmax[x]=ans[x]=max(d,d*size[x]);
	tag[x]=1;rev[x]=0;
}

void push_down(int x)
{
	if (rev[x])
	{
		if (ch[x][0]) reverse(ch[x][0]);
		if (ch[x][1]) reverse(ch[x][1]);
		rev[x]=0;
	}
	if (tag[x])
	{
		if (ch[x][0]) replace(ch[x][0],w[x]);
		if (ch[x][1]) replace(ch[x][1],w[x]);
		tag[x]=0;
	}
}

int dir(int x)
{
	return x==ch[fa[x]][1];
}

void rotate(int x)
{
	int y,z,a,b,c;
	y=fa[x];z=fa[y];b=dir(x);a=ch[x][!b];
	if (z==0) root=x;
	else
	{
		c=dir(y);ch[z][c]=x;
	}
	fa[x]=z;fa[y]=x;ch[x][!b]=y;ch[y][b]=a;
	if (a) fa[a]=y;
	update(y);update(x);
}

void down(int x)
{
	if (fa[x]) down(fa[x]);
	push_down(x);
}

void splay(int x,int i)
{
	down(x);
	int y,z,b,c;
	while (fa[x]!=i)
	{
		y=fa[x];z=fa[y];
		if (z==i) rotate(x);
		else
		{
			b=dir(x);c=dir(y);
			if (b^c)
			{
				rotate(x);rotate(x);
			}
			else
			{
				rotate(y);rotate(x);
			}
		}
	}
}

int find_k(int x,int k)
{
	push_down(x);
	if (size[ch[x][0]]==k-1) return x;
	if (size[ch[x][0]]>k-1) return find_k(ch[x][0],k);
	else return find_k(ch[x][1],k-size[ch[x][0]]-1); 
}

void build_tree(int l,int r,int tt)
{
	int mid=(l+r)/2;
	w[tt]=a[mid];
	if (l==r) {sum[tt]=lmax[tt]=rmax[tt]=ans[tt]=w[tt];size[tt]=1;return;}
	if (l<mid) {ch[tt][0]=newnode();fa[ch[tt][0]]=tt;build_tree(l,mid-1,ch[tt][0]);}
	if (mid<r) {ch[tt][1]=newnode();fa[ch[tt][1]]=tt;build_tree(mid+1,r,ch[tt][1]);}
	update(tt);
}

int Query(int l,int num)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],num+1);splay(y,x);
	return sum[ch[y][0]];
}

void Insert(int l,int num)
{
	for (int i=1;i<=num;i++) scanf("%d",&a[i]);
	int x=find_k(root,l+1);splay(x,0);
	int y=find_k(ch[x][1],1);splay(y,x);
	ch[y][0]=newnode();fa[ch[y][0]]=y;
	build_tree(1,num,ch[y][0]);
	update(y);update(x);
}

void erase(int x)
{
	if (!x) return;
	st[++top]=x;
	if (ch[x][0]) erase(ch[x][0]);
	if (ch[x][1]) erase(ch[x][1]);
}

void Delete(int l,int num)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],num+1);splay(y,x);
	erase(ch[y][0]);
	fa[ch[y][0]]=0;ch[y][0]=0;
	update(y);update(x);
}

void Reverse(int l,int num)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],num+1);splay(y,x);
	reverse(ch[y][0]);
	update(y);update(x);
}

void Replace(int l,int num,int d)
{
	int x=find_k(root,l);splay(x,0);
	int y=find_k(ch[x][1],num+1);splay(y,x);
	replace(ch[y][0],d);
	update(y);update(x);
}

int main()
{
	lmax[0]=rmax[0]=ans[0]=-inf;
	tot=2;root=1;
	fa[1]=0;size[1]=2;ch[1][1]=2;w[1]=sum[1]=lmax[1]=rmax[1]=-inf;
	fa[2]=1;size[2]=1;w[2]=sum[2]=lmax[2]=rmax[2]=-inf;
	scanf("%d%d",&n,&T);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	ch[2][0]=newnode();fa[ch[2][0]]=2;
	build_tree(1,n,ch[2][0]);
	update(2);update(1);
	while (T--)
	{
		int x,y,z;
		scanf("%s",s);
		if (s[2]=='X') printf("%d\n",ans[root]);
		if (s[0]=='G')
		{
			scanf("%d%d",&x,&y);
			printf("%d\n",Query(x,y));
		}
		if (s[0]=='I')
		{
			scanf("%d%d",&x,&y);
			Insert(x,y);
		}
		if (s[0]=='D')
		{
			scanf("%d%d",&x,&y);
			Delete(x,y);
		}
		if (s[0]=='R')
		{
			scanf("%d%d",&x,&y);
			Reverse(x,y);
		}
		if (s[4]=='-')
		{
			scanf("%d%d%d",&x,&y,&z);
			Replace(x,y,z);
		}
	}
	return 0;
}


你可能感兴趣的:(【bzoj1500】[NOI2005]维修数列 Splay)