【洛谷P2710】数列

题目

题目链接:https://www.luogu.com.cn/problem/P2710
维护一个数列,共 \(7\) 种操作:

I. INSERT x n a1 a2 .. an 在第 \(x\) 个数后插入 \(n\) 个数分别为 \(a_1\dots a_n\)。

II. DELETE x n 删除第 \(x\) 个数开始的 \(n\) 个数。

III. REVERSE x n 翻转第 \(x\) 个数开始的 \(n\) 个数的区间。

IV. MAKE-SAME x n t 将第 \(x\) 个数开始的 \(n\) 个数统一改为 \(t\)。

V. GET-SUM x n 输出第 \(x\) 个数开始的 \(n\) 个数的和。

VI. GET x 输出第 \(x\) 个数的值。

VII. MAX-SUM x n 输出第 \(x\) 个数开始的 \(n\) 个数的最大连续子序列和。

思路

很明显可以用 Splay。然后这道毒瘤题调了我至少八九小时 /kk。
主要原因还是对 Splay 不熟。其实做这道题主要目的也是练习 Splay。
【洛谷P2710】数列
代码长度一度达到 5kb /fad。


操作一、二、三、五、六都是 Spaly 的基本操作。
对于区间推平,我们在每一个区间维护一个推平标记,下次递归到子树的时候再下传标记。
对于区间最大子段和,维护区间最大前缀和,区间最大后缀和即可。转移的时候可以通过这两项来计算出区间最大子段和。
然后就没什么好说的了。这道题主要考察的不是算法,而是心态。

代码

#include <bits/stdc++.h>
using namespace std;

const int N=500010,Inf=1e9;
int n,m,rt,last;
char type[10];

struct Splay
{
	int tot,ch[N][2],lazy[N],size[N],val[N],fa[N],sum[N],lmax[N],rmax[N],smax[N],filp[N];
	
	Splay()
	{
		memset(lazy,0x3f3f3f3f,sizeof(lazy));
		memset(smax,0xcf,sizeof(smax));
	}
	
	int pos(int x)
	{
		return ch[fa[x]][1]==x;
	}
	
	void pushup(int x)
	{
		int lc=ch[x][0],rc=ch[x][1];
		sum[x]=sum[lc]+sum[rc]+val[x];
		size[x]=size[lc]+size[rc]+1;
		lmax[x]=max(lmax[lc],sum[lc]+val[x]+lmax[rc]);
		rmax[x]=max(rmax[rc],sum[rc]+val[x]+rmax[lc]);
		smax[x]=max(max(smax[lc],smax[rc]),rmax[lc]+val[x]+lmax[rc]);
	}
	
	void pushdown(int x)
	{
		int lc=ch[x][0],rc=ch[x][1];
		if (lazy[x]!=0x3f3f3f3f)
		{
			if (lc)
			{
				val[lc]=lazy[lc]=lazy[x];
				sum[lc]=lazy[x]*size[lc];
				lmax[lc]=rmax[lc]=max(lazy[x],0)*size[lc];
				smax[lc]=max(lazy[x],0)*(size[lc]-1)+lazy[x];
			}
			if (rc)
			{
				val[rc]=lazy[rc]=lazy[x];
				sum[rc]=lazy[x]*size[rc];
				lmax[rc]=rmax[rc]=max(lazy[x],0)*size[rc];
				smax[rc]=max(lazy[x],0)*(size[rc]-1)+lazy[x];
			}
			lazy[x]=0x3f3f3f3f;
		}
		if (filp[x])
		{
			filp[lc]^=1; filp[rc]^=1; filp[x]=0;
			swap(ch[lc][0],ch[lc][1]),swap(lmax[lc],rmax[lc]);
			swap(ch[rc][0],ch[rc][1]),swap(lmax[rc],rmax[rc]);
		}
	}
	
	void build()
	{
		tot++;
		val[tot]=sum[tot]=-Inf; size[tot]=1;
		lmax[tot]=rmax[tot]=0; smax[tot]=-Inf;
		tot++;
		val[tot]=sum[tot]=Inf; size[tot]=1;
		lmax[tot]=rmax[tot]=smax[tot]=Inf;
		ch[1][1]=2; fa[2]=rt=1;
		pushup(2); pushup(1);
	}
	
	void rotate(int x)
	{
		int y=fa[x],z=fa[y],k=pos(x),c=ch[x][k^1];
		pushdown(x);
		fa[x]=z; ch[z][pos(y)]=x;
		fa[y]=x; ch[x][k^1]=y;
		fa[c]=y; ch[y][k]=c;
		pushup(y); pushup(x);
	}
	
	void splay(int x,int f=0)
	{
		while (fa[x]!=f)
		{
			int y=fa[x],z=fa[y];
			if (z==f) rotate(x);
			else if (pos(x)==pos(y)) rotate(y),rotate(x);
			else rotate(x),rotate(x);
		}
		if (!f) rt=x;
	}
	
	void ins(int x,int v)
	{
		int p=rt,f=0,k=0;
		while (p)
		{
			pushdown(p); f=p;
			if (size[ch[p][0]]>=x) p=ch[p][0],k=0;
				else x-=(size[ch[p][0]]+1),p=ch[p][1],k=1;
		}
		fa[++tot]=f; 
		val[tot]=sum[tot]=v; size[tot]=1;
		lmax[tot]=rmax[tot]=max(v,0); smax[tot]=v;
		if (f) ch[f][k]=tot;
			else rt=tot;
		pushup(tot); pushup(f);
		splay(tot);
	}
	
	int find(int k)
	{
		int p=rt;
		while (k)
		{
			pushdown(p);
			if (k==size[ch[p][0]]+1) break;
			if (k<=size[ch[p][0]]) p=ch[p][0];
				else k-=(size[ch[p][0]]+1),p=ch[p][1];
		}
		splay(p);
		return p;
	}
	
	void del(int l,int r)
	{
		int x=find(l-1),y=find(r+1);
		splay(x); splay(y,rt);
		ch[y][0]=0;
		pushup(y); pushup(x);
	}
	
	void rev(int l,int r)
	{
		int x=find(l-1),y=find(r+1);
		splay(x); splay(y,rt);
		x=ch[y][0]; filp[x]^=1;
		swap(ch[x][0],ch[x][1]); 
		swap(lmax[x],rmax[x]);
		pushup(y); pushup(fa[y]);
	}
	
	void update(int l,int r,int v)
	{
		int x=find(l-1),y=find(r+1);
		splay(x); splay(y,rt);
		x=ch[y][0];
		lazy[x]=val[x]=v; sum[x]=v*size[x];
		lmax[x]=rmax[x]=max(v,0)*size[x];
		smax[x]=max(v,0)*(size[x]-1)+v;
		pushup(y); pushup(fa[y]);
	}
	
	int querysum(int l,int r)
	{
		int x=find(l-1),y=find(r+1);
		splay(x); splay(y,rt);
		return sum[ch[y][0]];
	}
	
	int querymax(int l,int r)
	{
		int x=find(l-1),y=find(r+1);
		splay(x); splay(y,rt);
		return smax[ch[y][0]];
	}
}splay;

int main()
{
	scanf("%d%d",&n,&m);
	splay.build();
	for (int i=1,x;i<=n;i++)
	{
		scanf("%d",&x);
		splay.ins(i,x);
	}
	for (int i=1,x,k,t;i<=m;i++)
	{
		for (int i=0;i<=9;i++) type[i]=' ';
		scanf("%s",type);
		if (type[0]=='I')
		{
			scanf("%d%d",&x,&k);
			for (int j=1;j<=k;j++)
			{
				scanf("%d",&t);
				splay.ins(x+j,t);
			}
		}
		else if (type[0]=='D')
		{
			scanf("%d%d",&x,&k);
			splay.del(x+1,x+k);
		}
		else if (type[0]=='R')
		{
			scanf("%d%d",&x,&k);
			splay.rev(x+1,x+k);
		}
		else if (type[0]=='M' && type[2]=='K')
		{
			scanf("%d%d%d",&x,&k,&t);
			splay.update(x+1,x+k,t);
		}
		else if (type[0]=='G' && type[4]=='S')
		{
			scanf("%d%d",&x,&k);
			printf("%d\n",last=splay.querysum(x+1,x+k));
		}
		else if (type[0]=='G')
		{
			scanf("%d",&x);
			printf("%d\n",last=splay.querysum(x+1,x+1));
		}
		else if (type[0]=='M' && type[2]=='X')
		{
			scanf("%d%d",&x,&k);
			printf("%d\n",last=splay.querymax(x+1,x+k));
		}
	}
	return 0;
}
上一篇:单例设计模式线程安全问题


下一篇:设计模式——单例模式