Written with StackEdit.

Description

请写一个程序,要求维护一个数列,支持以下 \(6\) 种操作:
请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格
bzoj 1500 维修序列

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

Solution

  • 大数据结构题...敲完这道题保证神清气爽...
  • 本蒟蒻的做法是用一棵非旋\(treap\)维护这个数列.
  • \(split\)时按照\(size\)分割.这样分割出的区间是以下标排序的.
    • \(insert\):将给的数中序遍历,建成一棵小树后,再插入整颗树中.这样个人感性理解会比较方便.初始化也可以这样做.
    • \(delete\):将给的区间\(split\)出来,合并两旁的树.注意开内存栈回收空间.
    • \(make-same\):将给的区间\(split\)出来,打上对应的标记.
    • \(reverse\):将给的区间\(split\)出来,打上对应的标记.
    • \(getsum\):将给的区间\(split\)出来,直接返回\(pushup\)时维护的对应答案.
    • \(maxsum\):直接返回整颗树根节点\(pushup\)时维护的对应答案.
  • 这道题的细节部分主要在\(pushup\)函数内,而因为此题中最大子段和要求选出的子段不为空(题面没说清,根据数据感性理解的),所以初始化虚拟节点\(0\)的时候也是比较讲究的.具体可以看下面的代码.
  • 所以我为啥还要去学Splay呢.
#include<bits/stdc++.h>
#define inf 1e9
using namespace std;
typedef long long LoveLive;
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		{
			fh=-1;
			jp=getchar();
		}
	while (jp>='0'&&jp<='9')
		{
			out=out*10+jp-'0';
			jp=getchar();
		}
	return out*fh;
}
const int MAXN=5e5+10;
struct FhqTreap
{
	int x,y,z,p,q;
	int idx;
	int stk[MAXN],top;
	int w[MAXN];
	int root;
	struct node{
		int lson,rson,siz,key,weight;
		int rev,cov;//reverse and cover
		int sum,mx;//总和,最大子段和
		int lm,rm;//从左/右边开始的最大子段和 
	}treap[MAXN];
	FhqTreap()
		{
			idx=0;
			top=0;
			root=0;
			top=0;
			treap[0].sum=0;
			treap[0].siz=0;
			treap[0].mx=-inf;//特别注意.否则pushup最大子段和的时候,可能会出现空的子段. 
			treap[0].lm=0;
			treap[0].rm=0;
			treap[0].rev=0;
			treap[0].cov=inf;
		}
	#define rt treap[o]
	#define ls treap[treap[o].lson]
	#define rs treap[treap[o].rson]
	inline int newnode(int key)
		{
			int o=top?stk[top--]:++idx;
			rt.lson=rt.rson=0;
			rt.siz=1;
			rt.key=key;
			rt.weight=rand();
			rt.rev=0;
			rt.cov=inf;
			rt.sum=key;
			rt.mx=key;
			rt.lm=key;
			rt.rm=key;
			return o;
		}
	void pushup(int o)
		{
			if(!o)
				return;
			rt.siz=ls.siz+rs.siz+1;
			rt.sum=ls.sum+rs.sum+rt.key;
			rt.lm=rt.key;
			rt.lm=max(ls.lm,max(ls.sum+rt.key,ls.sum+rt.key+rs.lm));
			rt.rm=rt.key;
			rt.rm=max(rs.rm,max(rs.sum+rt.key,rs.sum+rt.key+ls.rm));
			rt.mx=rt.key;
			rt.mx=max((ls.rm>0?ls.rm:0)+rt.key+(rs.lm>0?rs.lm:0),max(ls.mx,rs.mx));//若子节点不存在,mx赋为-inf,强制选择了rt,保证不为空. 
		}
	void upend(int o)
		{
			swap(rt.lson,rt.rson);
			swap(rt.lm,rt.rm);
			rt.rev^=1;	
		}
	void cover(int o,int val)
		{
			rt.key=val;
			rt.sum=rt.siz*val;
			rt.mx=max(rt.sum,val);//字段长度至少为1
			rt.lm=max(rt.sum,0);// remained to be updated
			rt.rm=max(rt.sum,0); 
			rt.cov=val;
		}
	void pushdown(int o)
		{
			if(rt.rev)
				{
					if(rt.lson)
						upend(rt.lson);
					if(rt.rson)
						upend(rt.rson);
				}
			if(rt.cov!=inf)
				{
					if(rt.lson)
						cover(rt.lson,rt.cov);
					if(rt.rson)
						cover(rt.rson,rt.cov);
				}
			rt.rev=0;
			rt.cov=inf;
		}
	void recover(int o)
		{
			if(!o)
				return;
			stk[++top]=o;
			recover(rt.lson);
			recover(rt.rson);
		}
	void split(int &x,int &y,int k,int o)//按子树大小分,前k个分到x中,其余y中 
		{
			if(!o)
				x=y=0;
			else
				{
					pushdown(o);
					if(k<=ls.siz)
						{
							y=o;
							split(x,rt.lson,k,rt.lson);
						}
					else
						{
							x=o;
							split(rt.rson,y,k-ls.siz-1,rt.rson);
						}
					pushup(o);
				}
		}
	int merge(int x,int y)
		{
			if(x==0 || y==0)
				return x+y;
			pushdown(x);
			pushdown(y);
			if(treap[x].weight<treap[y].weight)
				{
					treap[x].rson=merge(treap[x].rson,y);
					pushup(x);
					return x;
				}
			else
				{
					treap[y].lson=merge(x,treap[y].lson);
					pushup(y);
					return y;
				}
		}
	int BuildTree(int l,int r)//以w[l]~w[r]建树,返回树根标号 
		{
			if(l>r)
				return 0;
			int mid=(l+r)>>1;
			int o=newnode(w[mid]);
			rt.lson=BuildTree(l,mid-1);
			rt.rson=BuildTree(mid+1,r);
			pushup(o);
			return o;
		}
	int getdata(int tot)
		{
			for(int i=1;i<=tot;++i)
				w[i]=read();
			return BuildTree(1,tot);
		}
	void ins(int pos,int tot)
		{
			int o=getdata(tot);
			split(x,y,pos,root);
			x=merge(x,o);
			root=merge(x,y);
		}
	void del(int pos,int tot)
		{
			split(x,y,pos-1,root);
			split(p,q,tot,y);
			root=merge(x,q);
			recover(p);
		}
	void update(int pos,int tot,int c)
		{
			split(x,y,pos-1,root);
			split(p,q,tot,y);
			cover(p,c);
			root=merge(x,merge(p,q));
		}
	void rev(int pos,int tot)
		{
			split(x,y,pos-1,root);
			split(p,q,tot,y);
			upend(p);
			root=merge(x,merge(p,q));
		}
	int getsum(int pos,int tot)
		{
			split(x,y,pos-1,root);
			split(p,q,tot,y);
			int res=treap[p].sum;
			root=merge(x,merge(p,q));
			return res;
		}
	int maxsum()
		{
			return treap[root].mx;
		}
	void pr(int o)
		{
			if(!o)
				return;
			pr(rt.lson);
			printf("%d ",rt.key);
			pr(rt.rson);
		}
	void print()
		{
			pr(root);
			puts("");
		}
}T;
int n,m;
int main()
{
	srand(time(NULL));
	n=read(),m=read();
	T.ins(0,n);
//	T.print();
	char op[50];
	int pos,tot,c;
	for(int i=1;i<=m;++i)
		{
			scanf("%s",op);
			if(op[0]=='I')
				{
					pos=read();
					tot=read();
					T.ins(pos,tot);
				}
			else if(op[0]=='D')
				{
					pos=read();
					tot=read();
					T.del(pos,tot);
				}
			else if(op[0]=='M' && op[2]=='K')
				{
					pos=read();
					tot=read();
					c=read();
					T.update(pos,tot,c);
				}
			else if(op[0]=='R')
				{
					pos=read();
					tot=read();
					T.rev(pos,tot);
				}
			else if(op[0]=='G')
				{
					pos=read();
					tot=read();
					int ans=T.getsum(pos,tot);
					printf("%d\n",ans);
				}
			else if(op[0]=='M' && op[2]=='X')
				{
					int ans=T.maxsum();
					printf("%d\n",ans);
				}
		}
	return 0;
}

相关文章: