ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【P2710 数列】【Splay】

2022-02-07 21:02:06  阅读:205  来源: 互联网

标签:ch 数列 标记 int rev same Splay P2710 pushdown


【P2710 数列】【Splay】

Splay的经典模板题,细节非常多。这里主要记录一些容易错的点,和不太容易理解的地方

  1. pushdown 函数和懒标记的含义
    有两种写法:
    第一种是懒标记代表其子节点是否更新,这也是通常的写法(线段树和平衡树都是),在这种写法中,pushdown的作用是将子节点的信息更新。
    这样做的好处是在很多情况下pushup(x)的时候,不需要先pushdown(son(x))了【具体见代码】
    在查询中可能也会更方便一些
    第二种是懒标记代表该节点是否更新,很少有人用这种写法,在这种写法中pushdown的作用是更新该节点,比上一种写法要少写“一半”(只更新一个点),但是在查询或pushup的时候得多考虑考虑是否需要pushdown了(可以把第一种写法理解为比第二种写法更快一步)
  2. 标记之间的顺序与覆盖
    不论是线段树还是平衡树,标记之间都要自定义一个顺序(例如线段树2),有的标记之间可以覆盖,如本题中的same就可以覆盖rev。
    笔者在本题中犯的一个错误就是在pushdown时,先判断same标记,若为真,就不再处理rev标记,但是这样做就导致rev标记没有清空,下次查到该点时还会再更新。
    对于这种情况有两种处理方式:
    一种是只让same标记和rev标记最多存在一种,即makesame时把rev清空,reverse时若same为真则return。
    第二种就是在pushdown时确保把所有标记都清空。
  3. 内存回收
    原理很简单,把删除的点用一个栈存起来,添加新点时优先从栈中取点。
    再删除中通常是用splay的提取区间操作,用dfs遍历一颗子树。
    笔者犯下的错误是在dfs中采取中序遍历方式,且在访问完一个点后就将该点信息清空,这样的话由于该点的信息已被清空,就无法遍历右子树了。所以一定要遍历完整颗子树后再将信息清空。

最后贴一下代码

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

inline int read()
{
	register int x=0,w=1;
	register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
const int N=2e5+100,inf=1e8;
int n,m,a[N],nodes[N],top,rt;
struct node{
	int p,s[2],siz,rev,same,sum,val,ls,rs,ms;
}t[N];
char op[10];
void clear(int x)
{
	t[x].p=t[x].s[0]=t[x].s[1]=t[x].siz=t[x].rev=t[x].same=t[x].sum=t[x].val=t[x].ls=t[x].rs=t[x].ms=0;
}
int get(int x)
{
	return t[t[x].p].s[1]==x;
}
void pushup(int x)
{
	t[x].siz=t[t[x].s[0]].siz+t[t[x].s[1]].siz+1;
	t[x].sum=t[t[x].s[0]].sum+t[t[x].s[1]].sum+t[x].val;
	t[x].ls=max(t[x].s[0]?t[t[x].s[0]].ls:-inf,t[t[x].s[0]].sum+t[x].val+max(0,t[t[x].s[1]].ls));
	t[x].rs=max(t[x].s[1]?t[t[x].s[1]].rs:-inf,t[t[x].s[1]].sum+t[x].val+max(0,t[t[x].s[0]].rs));
	t[x].ms=max(max(t[x].s[0]?t[t[x].s[0]].ms:-inf,t[x].s[1]?t[t[x].s[1]].ms:-inf),t[x].val+max(0,t[t[x].s[0]].rs)+max(0,t[t[x].s[1]].ls));
}
void makesame(int x,int c)
{
	t[x].val=c;
	t[x].rev=0,t[x].same=1;
	t[x].sum=t[x].siz*c;
	if(c>=0) t[x].ls=t[x].rs=t[x].ms=t[x].sum;
	else t[x].ls=t[x].rs=t[x].ms=c;
}
void reverse(int x)
{
	if(t[x].same) return;
	swap(t[x].s[0],t[x].s[1]);
	swap(t[x].ls,t[x].rs);
	t[x].rev^=1;
}
void pushdown(int x)
{
	if(t[x].same)
	{
		t[x].same=0;
//		t[x].rev=0;
		if(t[x].s[0]) makesame(t[x].s[0],t[x].val);
		if(t[x].s[1]) makesame(t[x].s[1],t[x].val);
		return;
	}
	if(t[x].rev)
	{
		t[x].rev=0;
		if(t[x].s[0]) reverse(t[x].s[0]);
		if(t[x].s[1]) reverse(t[x].s[1]);
	}
}
int rkget(int k)
{
	int now=rt;
	while(now)
	{
		pushdown(now);
		if(k<=t[t[now].s[0]].siz) now=t[now].s[0];
		else
		{
			if(k==t[t[now].s[0]].siz+1) return now;
			k-=t[t[now].s[0]].siz+1;
			now=t[now].s[1];
		}
	}
}
int build(int l,int r,int p)
{
	int mid=l+r>>1;
	int u=nodes[top--];
	t[u].val=a[mid];
	t[u].p=p;
	if(l<mid) t[u].s[0]=build(l,mid-1,u);
	if(r>mid) t[u].s[1]=build(mid+1,r,u);
	pushup(u);
	return u;
}
void rotate(int x)
{
	int y=t[x].p,z=t[y].p,k=get(x);
	t[z].s[get(y)]=x;t[x].p=z;
	t[y].s[k]=t[x].s[k^1];t[t[y].s[k]].p=y;
	t[x].s[k^1]=y;t[y].p=x;
	pushup(y);pushup(x);
}
void splay(int x,int k)
{
	for(int y=t[x].p;y!=k;rotate(x),y=t[x].p)
	  if(t[y].p!=k) rotate(get(y)==get(x)?y:x);
	if(!k) rt=x; 
}
void dfs(int x)
{
	if(t[x].s[0]) dfs(t[x].s[0]);
	if(t[x].s[1]) dfs(t[x].s[1]);
	nodes[++top]=x;clear(x);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<N;++i) nodes[++top]=i;
    rt=build(0,n+1,0);
    for(int i=1;i<=m;++i)
    {
    	scanf("%s",op);int x=read();
    	if(!strcmp(op,"INSERT"))
    	{
    		int cnt=read();
    		for(int j=1;j<=cnt;++j)
    		{
    			a[j]=read();
			}
			int l=rkget(x+1),r=rkget(x+2);
			splay(l,0);splay(r,l);
			t[r].s[0]=build(1,cnt,r);
			pushup(r);pushup(l);
		}
		else if(!strcmp(op,"DELETE"))
		{
			int cnt=read();
			int l=rkget(x),r=rkget(x+cnt+1);
			splay(l,0);splay(r,l);
			dfs(t[r].s[0]);
			t[r].s[0]=0;
			pushup(r);pushup(l);
		}
		else if(!strcmp(op,"REVERSE"))
		{
			int cnt=read();
			int l=rkget(x),r=rkget(x+cnt+1);
			splay(l,0);splay(r,l);
			reverse(t[r].s[0]);
			pushup(r);pushup(l);
		}
		else if(!strcmp(op,"MAKE-SAME"))
		{
			int cnt=read(),c=read();
			int l=rkget(x),r=rkget(x+cnt+1);
			splay(l,0);splay(r,l);
			makesame(t[r].s[0],c);
			pushup(r);pushup(l);
		}
		else if(!strcmp(op,"GET-SUM"))
		{
			int cnt=read();
			int l=rkget(x),r=rkget(x+cnt+1);
			splay(l,0);splay(r,l);
			printf("%d\n",t[t[r].s[0]].sum);
		}
		else if(!strcmp(op,"GET"))
		{
			int l=rkget(x+1);splay(l,0);
			printf("%d\n",t[rt].val);
		}
		else
		{
			int cnt=read();
			int l=rkget(x),r=rkget(x+cnt+1);
			splay(l,0);splay(r,l);
			printf("%d\n",t[t[r].s[0]].ms);
		}
	}
	return 0;
}

标签:ch,数列,标记,int,rev,same,Splay,P2710,pushdown
来源: https://www.cnblogs.com/glq-Blog/p/15869171.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有