BZOJ1500维修数列 [待修缮]

在这里存一波splay模板题,啃起来有点难。。

Description

请写一个程序,要求维护一个数列,支持以下 6 种操作:

请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格

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

 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include <sstream>
#define inf 800000000
#define ll long long
#define mod 1000000007
using namespace std;
const int maxn=500000;

int n,m,i,nnode=0,rest=0,root=0,root1,pos,tot,k,q[maxn],c[maxn][2],size[maxn],pre[maxn],num[maxn],maxsum[maxn],maxpre[maxn],maxpos[maxn],same[maxn],rev[maxn],sum[4000005],s[maxn];
char str[10];
void update(int x)
{
	size[x]=size[c[x][0]]+size[c[x][1]]+1;sum[x]=sum[c[x][0]]+sum[c[x][1]]+num[x];
	maxsum[x]=max(max(maxsum[c[x][0]],maxsum[c[x][1]]),maxpos[c[x][0]]+num[x]+maxpre[c[x][1]]);
	maxpre[x]=max(sum[c[x][0]]+maxpre[c[x][1]]+num[x],maxpre[c[x][0]]);maxpos[x]=max(sum[c[x][1]]+maxpos[c[x][0]]+num[x],maxpos[c[x][1]]);
}

void marksame(int x,int c)
{
	same[x]=c;
	if (c==1001) c=0;
	num[x]=c;sum[x]=size[x]*c;
	if (c>=0) maxsum[x]=maxpre[x]=maxpos[x]=size[x]*c; else maxpre[x]=maxpos[x]=0,maxsum[x]=c;
}
void markrev(int x)
{
	swap(c[x][0],c[x][1]);
	swap(maxpre[x],maxpos[x]);
	rev[x]^=1;
}
void down(int x)
{
	if (same[x])
	{
		if (c[x][0]) marksame(c[x][0],same[x]); if (c[x][1]) marksame(c[x][1],same[x]);
		same[x]=0;
	}
	if (rev[x])
	{
		if (c[x][0]) markrev(c[x][0]);if (c[x][1]) markrev(c[x][1]);
		rev[x]=0;
	}
}
void newnode(int &x,int fa,int k)
{
	if (rest) x=s[rest--];else x=++nnode;
	pre[x]=fa;num[x]=k;	size[x]=1;
	c[x][0]=c[x][1]=same[x]=rev[x]=0;
	sum[x]=maxsum[x]=k;
	maxpre[x]=maxpos[x]=max(k,0);
}
void rot(int x,int kind)
{
	int y=pre[x];int z=pre[y];down(x);
	c[y][!kind]=c[x][kind];pre[c[x][kind]]=y;
	c[x][kind]=y;pre[y]=x;
	pre[x]=z;if (z) c[z][c[z][1]==y]=x;
	update(y);update(x);if (z) update(z);
}
void splay(int x,int goal)
{
	int y,z,kind;
	while (pre[x]!=goal)
	{
		y=pre[x];down(y);
		if (pre[y]==goal) rot(x,c[y][0]==x);
		else
		{
			z=pre[y];down(z);kind=c[z][0]==y;
			if (c[y][!kind]==x) rot(y,kind);else rot(x,!kind);
			rot(x,kind);
		}
	}
	if (goal==0) root=x;
}
int findkth(int x,int k)//加处理
{
	down(x);
	if (size[c[x][0]]>=k) return findkth(c[x][0],k);
	if (k==size[c[x][0]]+1) return x;
	if (k>size[c[x][0]]+1) return findkth(c[x][1],k-size[c[x][0]]-1);
}
void build(int &x,int fa,int l,int r)
{
	if (l>r) return;
	int mid=(l+r)/2;
	newnode(x,fa,q[mid]);
	if (l==r) return;
	build(c[x][0],x,l,mid-1);build(c[x][1],x,mid+1,r);
	update(x);
}
void insert(int pos,int tot)
{
	int i;
	for (i=1;i<=tot;i++)
		scanf("%d",&q[i]);
	build(root1,0,1,tot);
	splay(findkth(root,pos+1),0);
	splay(findkth(root,pos+2),root);
	c[c[root][1]][0]=root1;pre[root1]=c[root][1];
	update(c[root][1]);update(root);
}
void erase(int x)
{
	if (!x) return;
	s[++rest]=x;
	erase(c[x][0]);erase(c[x][1]);
}
void deleted(int pos,int tot)
{
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	erase(c[c[root][1]][0]);
	c[c[root][1]][0]=0;
	update(c[root][1]);update(root);
}
void makesame(int pos,int tot,int k)
{
	if (k==0) k=1001;
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	marksame(c[c[root][1]][0],k);
	update(c[root][1]);update(root);
}
void markrev(int pos,int tot)
{
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	markrev(c[c[root][1]][0]);
	update(c[root][1]);update(root);

}
int getsum(int pos,int tot)
{
	splay(findkth(root,pos),0);splay(findkth(root,pos+tot+1),root);
	return sum[c[c[root][1]][0]];
}
void print(int x)
{
	if (c[x][0]) print(c[x][0]);
	printf("%d->num:%d,fa:%d,lc:%d,rc:%d,size:%d,sum:%d,maxpre:%d,maxpos:%d,maxsum:%d,same:%d,rev:%d\n",x,num[x],pre[x],c[x][0],c[x][1],size[x],sum[x],maxpre[x],maxpos[x],maxsum[x],same[x],rev[x]);
	if (c[x][1])print(c[x][1]);
}
int main()
{
	//freopen("shulie.in","r",stdin);
	//freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	newnode(root,0,-inf);newnode(c[root][1],root,-inf);
	insert(0,n);
	size[0]=pre[0]=same[0]=rev[0]=num[0]=sum[0]=maxpre[0]=maxpos[0]=0;maxsum[0]=-inf;
	for (i=1;i<=m;i++)
	{
		scanf("%s",&str);
		if (str[2]!='X') scanf("%d%d",&pos,&tot); else printf("%d\n",maxsum[root]);
		if (str[0]=='I') insert(pos,tot);
		if (str[0]=='D') deleted(pos,tot);
		if (str[0]=='M'&&str[2]=='K') scanf("%d",&k),makesame(pos,tot,k);
		if (str[0]=='R') markrev(pos,tot);
		if (str[0]=='G') printf("%d\n",getsum(pos,tot));
	}

}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值