955. 维护数列

题目链接

955. 维护数列

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

image

输入格式

\(1\) 行包含两个数 \(N\)\(M\)\(N\) 表示初始时数列中数的个数,\(M\) 表示要进行的操作数目。

\(2\) 行包含 \(N\) 个数字,描述初始时的数列。

以下 \(M\) 行,每行一条命令,格式参见问题描述中的表格。

输出格式

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

数据范围与约定

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

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

\(50\%\) 的数据中,任何时刻数列中最多含有 \(30000\) 个数;\(100\%\) 的数据中,任何时刻数列中最多含有 \(500000\) 个数。

\(100\%\) 的数据中,任何时刻数列中任何一个数字均在 \([-1000, 1000]\) 内。

\(100\%\) 的数据中,\(M \le 20000\),插入的数字总数不超过 \(4000000\) 个,输入文件大小不超过 \(20\ MBytes\)

输入样例:

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

解题思路

splay,动态开点,内存回收机制

开两个懒标记:\(same,rev\),表示修改和翻转标记,这两个标记其一的改变不会造成另一个的变化,可用常见数据结构维护,而操作涉及 \(插入\)\(删除\) 操作,线段树不好维护,而 \(splay\) 很好操作,即将对应区间操作转化为某一棵子树的操作,而由于插入的数据很大,为了避免超内存,可引入内存回收机制,即进行删除操作时可以将删除的节点编号回收。其他操作同线段树

  • 时间复杂度:\(O((n+m)\times logn)\)

代码

// Problem: 维护数列
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/957/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=5e5+5,inf=1e9;
int n,m,a[N],save[N],cnt,root;
struct Tr
{
	int s[2],p,v,sz,lmx,rmx,mx,sum,same,rev;
	void init(int _p,int _v)
	{
		p=_p;
		v=mx=sum=_v;
		s[0]=s[1]=same=rev=0;
		lmx=rmx=max(0,v);
		sz=1;
	}
}tr[N];
void pushup(int u)
{
	auto &p=tr[u],&l=tr[p.s[0]],&r=tr[p.s[1]];
	p.sz=l.sz+r.sz+1;
	p.sum=l.sum+r.sum+p.v;
	p.lmx=max(l.lmx,l.sum+p.v+r.lmx);
	p.rmx=max(r.rmx,r.sum+p.v+l.rmx);
	p.mx=max({l.mx,r.mx,l.rmx+p.v+r.lmx});
}
void pushdown(int u)
{
	auto &p=tr[u],&l=tr[tr[u].s[0]],&r=tr[tr[u].s[1]];
	if(p.rev)
	{
		swap(l.s[0],l.s[1]),swap(l.lmx,l.rmx);
		swap(r.s[0],r.s[1]),swap(r.lmx,r.rmx);
		p.rev=0,l.rev^=1,r.rev^=1;
	}
	if(p.same)
	{
		l.same=1,l.v=p.v,l.sum=l.sz*p.v;
		r.same=1,r.v=p.v,r.sum=r.sz*p.v;
		if(p.v>0)
		{
			l.lmx=l.rmx=l.mx=l.sum;
			r.lmx=r.rmx=r.mx=r.sum;
		}
		else
		{
			l.mx=p.v,l.lmx=l.rmx=0;
			r.mx=p.v,r.lmx=r.rmx=0;
		}
		tr[u].same=0;
	}
}
int build(int l,int r,int p)
{
	int u=save[cnt--];
	int mid=l+r>>1;
	tr[u].init(p,a[mid]);
	if(l<mid)tr[u].s[0]=build(l,mid-1,u);
	if(r>mid)tr[u].s[1]=build(mid+1,r,u);
	pushup(u);
	return u;
}
void rotate(int x)
{
	int y=tr[x].p,z=tr[y].p;
	int k=tr[y].s[1]==x;
	tr[z].s[tr[z].s[1]==y]=x,tr[x].p=z;
	tr[y].s[k]=tr[x].s[k^1],tr[tr[x].s[k^1]].p=y;
	tr[x].s[k^1]=y,tr[y].p=x;
	pushup(y),pushup(x);
}
void splay(int x,int k)
{
	while(tr[x].p!=k)
	{
		int y=tr[x].p,z=tr[y].p;
		if(z!=k)
		{
			if((tr[z].s[1]==y)^(tr[y].s[1]==x))rotate(x);
			else
				rotate(y);
		}
		rotate(x);
	}
	if(!k)root=x;
}
int get_k(int k)
{
	int u=root;
	while(u)
	{
		pushdown(u);
		if(tr[tr[u].s[0]].sz>=k)u=tr[u].s[0];
		else if(tr[tr[u].s[0]].sz+1==k)return u;
		else
			k-=tr[tr[u].s[0]].sz+1,u=tr[u].s[1];
	}
	return -1;
}
void dfs(int u)
{
	if(tr[u].s[0])dfs(tr[u].s[0]);
	if(tr[u].s[1])dfs(tr[u].s[1]);
	save[++cnt]=u;
}
int main()
{
	for(int i=1;i<N;i++)save[++cnt]=i;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    a[0]=a[n+1]=-inf;
    root=build(0,n+1,0);
    while(m--)
    {
    	char op[10];
    	int pos,k,c;
    	scanf("%s",op);
    	if(!strcmp(op,"INSERT"))
    	{
    		scanf("%d%d",&pos,&k);
    		for(int i=0;i<k;i++)scanf("%d",&a[i]);
    		int l=get_k(pos+1),r=get_k(pos+2);
    		splay(l,0),splay(r,l);
    		tr[r].s[0]=build(0,k-1,r);
    		pushup(r),pushup(l);
    	}
    	else if(!strcmp(op,"DELETE"))
    	{
    		scanf("%d%d",&pos,&k);
    		int l=get_k(pos),r=get_k(pos+k+1);
    		splay(l,0),splay(r,l);
    		dfs(tr[r].s[0]),tr[r].s[0]=0;
    		pushup(r),pushup(l);
    	}
    	else if(!strcmp(op,"MAKE-SAME"))
    	{
    		scanf("%d%d%d",&pos,&k,&c);
    		int l=get_k(pos),r=get_k(pos+k+1);
    		splay(l,0),splay(r,l);
    		auto &p=tr[r].s[0];
    		tr[p].v=c;
    		tr[p].same=1;
    		tr[p].sum=tr[p].sz*c;
    		if(c>0)tr[p].lmx=tr[p].rmx=tr[p].mx=tr[p].sum;
    		else
    			tr[p].lmx=tr[p].rmx=0,tr[p].mx=c;
    		pushup(r),pushup(l);
    	}
    	else if(!strcmp(op,"REVERSE"))
    	{
    		scanf("%d%d",&pos,&k);
    		int l=get_k(pos),r=get_k(pos+k+1);
    		splay(l,0),splay(r,l);
    		auto &p=tr[r].s[0];
    		tr[p].rev^=1;
    		swap(tr[p].lmx,tr[p].rmx);
    		swap(tr[p].s[0],tr[p].s[1]);
    		pushup(r),pushup(l);
    	}
    	else if(!strcmp(op,"GET-SUM"))
    	{
    		scanf("%d%d",&pos,&k);
    		int l=get_k(pos),r=get_k(pos+k+1);
    		splay(l,0),splay(r,l);
    		printf("%d\n",tr[tr[r].s[0]].sum);
    	}
    	else
    		printf("%d\n",tr[root].mx);
    }
    return 0;
}
posted @ 2022-07-16 10:30  zyy2001  阅读(19)  评论(0编辑  收藏  举报