Written with StackEdit.
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
Solution
- 大数据结构题...敲完这道题保证神清气爽...
我本蒟蒻的做法是用一棵非旋\(treap\)维护这个数列.- \(split\)时按照\(size\)分割.这样分割出的区间是以下标排序的.
- \(insert\):将给的数中序遍历,建成一棵小树后,再插入整颗树中.这样
个人感性理解会比较方便.初始化也可以这样做. - \(delete\):将给的区间\(split\)出来,合并两旁的树.注意开内存栈回收空间.
- \(make-same\):将给的区间\(split\)出来,打上对应的标记.
- \(reverse\):将给的区间\(split\)出来,打上对应的标记.
- \(getsum\):将给的区间\(split\)出来,直接返回\(pushup\)时维护的对应答案.
- \(maxsum\):直接返回整颗树根节点\(pushup\)时维护的对应答案.
- \(insert\):将给的数中序遍历,建成一棵小树后,再插入整颗树中.这样
- 这道题的细节部分主要在\(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;
}