维护序列[Splay]

题目描述

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

输入格式:

输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格

输出格式:

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

输入样例#1: 

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: 

-1
10
1
10

说明

你可以认为在任何时刻,数列中至少有 1 个数。

输入数据一定是正确的,即指定位置的数在数列中一定存在。

50%的数据中,任何时刻数列中最多含有 30 000 个数;

100%的数据中,任何时刻数列中最多含有 500 000 个数。

100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。

100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。


 Splay模板 + 类似线段树区间合并的东西

#include<bits/stdc++.h>
#define N 5000005
#define lc t[x].ch[0]
#define rc t[x].ch[1]
using namespace std;
int n,m,root,tot,a[N],p[N]; char ch[20];
struct Node{
	int ch[2],fa,val,size;
	int tag,lazy;
	int lmax,rmax,Max,sum;
}t[N];
int read(){
    int cnt=0,f=1;char ch=0;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')f=-1;}
    while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
    return cnt*f;
}
void Update(int x,int d){
	t[x].val=d,t[x].sum=d*t[x].size,t[x].lazy+=d;
	t[x].lmax=t[x].rmax=t[x].Max=max(d,d*t[x].size);
}
void Pushup(int x){
	t[x].size=t[lc].size+t[rc].size+1;
	t[x].sum=t[lc].sum+t[x].val+t[rc].sum;
	t[x].Max=max( max(t[lc].Max,t[rc].Max) , max(t[lc].rmax,0) + t[x].val + max(0,t[rc].lmax) );
	t[x].lmax=max(t[lc].lmax,t[lc].sum + t[x].val + max(0,t[rc].lmax));
	t[x].rmax=max(t[rc].rmax,t[rc].sum + t[x].val + max(0,t[lc].rmax));
}
int Build(int l,int r,int fa){
	if(l>r) return 0;
	int mid=(l+r)>>1,x=++tot; p[x]=mid; t[x].size=1;
	t[x].fa=fa,t[x].lmax=t[x].rmax=t[x].Max=t[x].sum=t[x].val=a[mid];
	lc=Build(l,mid-1,x),rc=Build(mid+1,r,x);
	Pushup(x); return x;
}
void Swap(int x){
	swap(lc,rc);
	swap(t[x].lmax,t[x].rmax);
	t[x].tag^=1;
}
void Pushdown(int x){
	if(t[x].tag){
		if(lc) Swap(lc);
		if(rc) Swap(rc);
		t[x].tag=0;
	}
	if(t[x].lazy){
		if(lc) Update(lc,t[x].lazy);
		if(rc) Update(rc,t[x].lazy);
		t[x].lazy=0;
	} 
}
void Pushpath(int x){
	if(t[x].fa) Pushpath(t[x].fa);
	Pushdown(x);
}
void rotate(int x){
	int y=t[x].fa,z=t[y].fa;
	int k=(t[y].ch[1]==x);
	t[z].ch[t[z].ch[1]==y]=x;
	t[x].fa=z;
	t[y].ch[k]=t[x].ch[k^1];
	t[t[x].ch[k^1]].fa=y;
	t[x].ch[k^1]=y;
	t[y].fa=x;
	Pushup(y),Pushup(x);
}
void Splay(int x,int goal){
	Pushpath(x);
	while(t[x].fa!=goal){
		int y=t[x].fa,z=t[y].fa;
		if(z!=goal)
			(t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
		rotate(x); 
	}if(goal==0) root=x;
}
int Find(int x,int k){
	Pushdown(x);
	if(t[lc].size>=k) return Find(lc,k);
	else if(t[lc].size+1<k) return Find(rc,k-t[lc].size-1);
	return x;
}
int main(){
	n=read(),m=read();
	for(int i=2;i<=n+1;i++) a[i]=read();
	a[1]=a[n+2]=-0x3fffffff; root=Build(1,n+2,0);
	while(m--){
		scanf("%s",ch);
		if(ch[0]=='I'){
			int x=read(),T=read(); 
			x=Find(root,x+1); Splay(x,0);
			int y=Find(rc,1); Splay(y,x);
			for(int i=1;i<=T;i++) a[i]=read();
			int o=Build(1,T,y);  
			t[y].ch[0]=o;
			Pushup(y),Pushup(x); 
		}
		if(ch[0]=='D'){
			int x=read(),T=read();
			x=Find(root,x); Splay(x,0);
			int y=Find(rc,T+1); Splay(y,x);
			t[t[y].ch[0]].fa=0,t[y].ch[0]=0;
			Pushup(y),Pushup(x);
		}
		if(ch[2]=='K'){
			int x=read(),T=read(),val=read();
			x=Find(root,x); Splay(x,0);
			int y=Find(rc,T+1); Splay(y,x);
			Update(t[y].ch[0],val); 
			Pushup(y),Pushup(x);
		}
		if(ch[0]=='R'){
			int x=read(),T=read();
			x=Find(root,x); Splay(x,0);
			int y=Find(rc,T+1); Splay(y,x);
			Swap(t[y].ch[0]);
			t[t[y].ch[0]].tag^=1; 
			Pushup(y),Pushup(x);
		}
		if(ch[0]=='G'){
			int x=read(),T=read();
			x=Find(root,x); Splay(x,0);
			int y=Find(rc,T+1);
			Splay(y,x); 
			printf("%d\n",t[t[y].ch[0]].sum);
		}
		if(ch[2]=='X') printf("%d\n",t[root].Max);
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值