BZOJ 1500: [NOI2005]维修数列 splay

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 15162  Solved: 5009
[Submit][Status][Discuss]

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT


真是一道splay练手好题  恶心死我了

由于做之前就知道 肯定很恶心 所以就先读了hzwer的代码

最后还是调了好久好久。。。。


数组含义如下

V 权值 sum 权值和 mx 最大连续和 mxl 从左开始最大连续和 mxr从右开始最大连续和

rev 是否翻转 tag 是否有权值覆盖


讲一下我觉得需要注意的地方

1. mxl mxr 可以为0

因为平衡树上的区间 mid 不包括在左右儿子中

2. 注意0号节点的V和mx

如果你也像BJ一样直接pushup 那么没有左右儿子就很有可能被0 pushup

3.注意更新时判是否有左右儿子

同上

4. rever最好不要像通常的只打标记 到了再转

应该像线段树一样 直接转 标记表示儿子是否要再打标记 因为还有一个赋值tag



#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=500100,inf=0X3f3f3f3f;

int root;
int ch[N][2],size[N],fa[N];
int V[N],sum[N],mx[N],mxl[N],mxr[N];
bool rev[N],tag[N];

int st[N],top,sz;

inline int newnode()
{return top ? st[top--] : ++sz;}

inline void pushup(int k)
{
	int ls=ch[k][0],rs=ch[k][1];
	size[k]=size[ls]+size[rs]+1;
	sum[k]=V[k]+sum[ls]+sum[rs];
	mx[k]=max(mx[ls],mx[rs]);
	mx[k]=max(mx[k],mxl[rs]+mxr[ls]+V[k]);
	mxl[k]=max(mxl[ls],sum[ls]+V[k]+mxl[rs]);
	mxr[k]=max(mxr[rs],sum[rs]+V[k]+mxr[ls]);
}

inline void pushdown(int k)
{
	int ls=ch[k][0],rs=ch[k][1];
	if(tag[k])
	{
		rev[k]=tag[k]=0;
		int val=V[k];
		if(ls)tag[ls]=1,V[ls]=val,sum[ls]=val*size[ls];
		if(rs)tag[rs]=1,V[rs]=val,sum[rs]=val*size[rs];
		if(val>=0)
		{
			if(ls)mxl[ls]=mxr[ls]=mx[ls]=sum[ls];
			if(rs)mxl[rs]=mxr[rs]=mx[rs]=sum[rs];
		}
		else 
		{
			if(ls)mxl[ls]=mxr[ls]=0,mx[ls]=val;
			if(rs)mxl[rs]=mxr[rs]=0,mx[rs]=val;
		}
	}
	
	if(rev[k])
	{
		rev[k]=0;
		rev[ls]^=1;rev[rs]^=1;
		swap(ch[ls][0],ch[ls][1]);
		swap(mxl[ls],mxr[ls]);
		swap(ch[rs][0],ch[rs][1]);
		swap(mxl[rs],mxr[rs]);
	}
}

int pos[N];

void build(int l,int r,int pre)
{
	if(l>r)return ;
	int mid=(l+r)>>1;
	fa[pos[mid]]=pos[pre];
	ch[pos[pre]][mid>pre]=pos[mid];
	build(l,mid-1,mid);
	build(mid+1,r,mid);
	pushup(pos[mid]);
}

int find(int k,int rk)
{
	pushdown(k);
	if(size[ch[k][0]]>=rk)
		return find(ch[k][0],rk);
	if(size[ch[k][0]]+1<rk)
		return find(ch[k][1],rk-1-size[ch[k][0]]);
	return k;
}

inline void rotate(int x,int &k)
{
	int y=fa[x],z=fa[y],l,r;
	l=(x==ch[y][1]);r=l^1;
	if(y==k) k=x;
	else ch[z][ch[z][1]==y]=x;
	fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
	ch[y][l]=ch[x][r];ch[x][r]=y;
	pushup(y);pushup(x);
}

void splay(int x,int &k)
{
	int y,z;
	while(x!=k)
	{
		y=fa[x];z=fa[y];
		if(y!=k)
		{
			if((ch[y][0]==x)^(ch[z][0]==y)) rotate(x,k);
			else rotate(y,k);
		}
		rotate(x,k);
	}
}

int split(int x,int y)
{
	x=find(root,x);y=find(root,y+2);
	splay(x,root);splay(y,ch[root][1]);
	return ch[y][0];
}

void recycle(int k)
{
	if(!k)return ;
	recycle(ch[k][0]);recycle(ch[k][1]);
	fa[k]=ch[k][0]=ch[k][1]=0;
	mx[k]=mxl[k]=mxr[k]=0;
	tag[k]=rev[k]=0;
	V[k]=sum[k]=0;
	size[k]=0;
	st[++top]=k;
}

void insert(int k,int num)
{
	for(int i=1;i<=num;++i)
	{
		pos[i]=newnode();
		V[pos[i]]=read();
	}
	build(1,num,0);
	int x=find(root,k+1),y=find(root,k+2);
	splay(x,root);splay(y,ch[x][1]);
	x=pos[(1+num)>>1];
	ch[y][0]=x;
	fa[x]=y;
	pushup(y);pushup(root);
}

void del(int x,int y)
{
	x=split(x,y);y=fa[x];
	ch[y][0]=0;
	recycle(x);
	pushup(y);
	pushup(root);
}

void modify(int x,int y,int val)
{
	x=split(x,y);
	tag[x]=1;
	V[x]=val;
	sum[x]=val*size[x];
	mxl[x]=mxr[x]=max(sum[x],0);
	mx[x]=max(sum[x],val);
	pushup(fa[x]);
	pushup(root);
}

void rever(int x,int y)
{
	x=split(x,y);
	if(!tag[x])
	{
		rev[x]^=1;
		swap(ch[x][0],ch[x][1]);
		swap(mxl[x],mxr[x]);
		pushup(fa[x]);pushup(root);
	}
}

int query_sum(int x,int y)
{
	x=split(x,y);
	return sum[x];
}

int main()
{
	int n=read(),Q=read();

	register int i;
	for(i=1;i<=n;++i)
		V[i+1]=read(),pos[i]=i;
	pos[n+1]=n+1;
	pos[n+2]=n+2;
	V[1]=V[n+2]=-inf;
	build(1,n+2,0);
	root=(n+3)>>1;sz=n+2;
	V[0]=mx[0]=-0X3f3f3f3f;
	char opt[10];
	register int k,num,val;int cnt=0;
	while(Q--)
	{
		scanf("%s",opt);
		switch(opt[0])
		{
			case 'I':
				k=read();num=read();
				insert(k,num);
				break;
			case 'D':
				k=read();num=read();
				del(k,k+num-1);
				break;
			case 'M':
				if(opt[2]=='K')
				{
					k=read();num=read();val=read();
					modify(k,k+num-1,val);
				}
				else
					print(mx[root]),puts("");
				break;
			case 'R':
				k=read();num=read();
				rever(k,k+num-1);
				break;
			case 'G':
				k=read();num=read();
				print(query_sum(k,k+num-1));puts("");
				break;
		}
	}
	return 0;
}
/*
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

-1
10
1
10
*/




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值