洛谷4146 序列终结者 (splay)

考虑维护编号树
注意标记的下放
k t h kth kth函数的时候也要进行下放标记。
需要对一段区间操作的时候,可以直接把 k t h ( l ) kth(l) kth(l)转到根,把 k t h ( r + 2 ) kth(r+2) kth(r+2)转到右儿子,那么根的右儿子的左子树就是要操作的区间,由于每一个子树都对应一个区间,所以说可以直接打标记来做。

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 1e5+1e2;
const int inf = -1e9;

int ch[maxn][2];
int size[maxn];
int mx[maxn];
int n,m;
int val[maxn];
int add[maxn];
int rev[maxn];
int fa[maxn];
int tot;

int newnode(int x)
{
   int now = ++tot;
   val[now]=mx[now]=x;
   size[now]=1;
   return now;
}

void update(int x)
{
	mx[x]=val[x];
	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
	if (ch[x][0]) mx[x]=max(mx[ch[x][0]],mx[x]);
	if (ch[x][1]) mx[x]=max(mx[ch[x][1]],mx[x]);
}

void jia(int x,int d)
{
	mx[x]+=d;
	val[x]+=d;
	add[x]+=d;
}

void reverse(int x)
{
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}

void pushdown(int x)
{
	if (add[x])
	{
		if (ch[x][0]) jia(ch[x][0],add[x]);
		if (ch[x][1]) jia(ch[x][1],add[x]);
		add[x]=0;
    }
    if (rev[x])
    {
    	if (ch[x][0]) reverse(ch[x][0]);
    	if (ch[x][1]) reverse(ch[x][1]);
    	rev[x]=0;
    }
}

int son(int x)
{
	if (ch[fa[x]][0]==x) return 0;
	else return 1;
}

void rotate(int x)
{
	int y = fa[x],z = fa[y];
    int b = son(x),c = son(y);
    pushdown(y);
    pushdown(x);
	ch[z][c]=x;
    fa[x]=z;
    ch[y][b]=ch[x][!b];
    fa[ch[x][!b]]=y;
    ch[x][!b]=y;
    fa[y]=x;
    update(y);
    update(x);
}

int root;

void splay(int x,int p)
{
   while (fa[x]!=p)
   {
   	  int y = fa[x],z = fa[y];
   	  int b = son(x),c = son(y);
   	  if (z==p) rotate(x);
   	  else
   	  {
   	  	 if (b==c)
   	  	 {
   	  	 	rotate(y);
   	  	 	rotate(x);
   	     }
   	     else
   	     {
   	     	rotate(x);
   	     	rotate(x);
   	     }
      }
   }
   if (p==0) root=x;
}

int kth(int x)
{
   int now = root;
   while (1)
   {
     pushdown(now);
	 if (x<=size[ch[now][0]]) now = ch[now][0];
	 else
	 {
	   if (x<=size[ch[now][0]]+1) return now;
	   x-=size[ch[now][0]]+1;
	   now = ch[now][1];
     }
   }
}

int a[maxn];

int build(int faa,int l,int r)
{
	if (l>r) return 0;
	int mid = l+r >> 1;
	int now = newnode(a[mid]);
	fa[now]=faa;
	ch[now][0]=build(now,l,mid-1);
	ch[now][1]=build(now,mid+1,r);
	update(now);
	return now;
}
	
int main()
{
  n=read();m=read();
  a[0]=a[n+1]=inf;
  for (int i=1;i<=n;i++) a[i]=0;
  root = build(0,0,n+1);
  for (int i=1;i<=m;i++)
  {
  	 int opt=read(),l=read(),r=read();
  	 if (opt==1)
  	 {
  	 	int x=read();
  	 	int qq = kth(l);
  	 	int hj = kth(r+2);
  	 	splay(qq,0);
  	 	splay(hj,qq);
  	 	int y = ch[hj][0];
  	 	mx[y]+=x;
  	 	val[y]+=x;
  	 	add[y]+=x;
  	 	pushdown(y);
     }
     if (opt==2)
     {
     	int qq = kth(l);
     	int hj = kth(r+2);
     	splay(qq,0);
     	splay(hj,qq);
     	int y = ch[hj][0];
     	swap(ch[y][0],ch[y][1]);
     	rev[y]^=1;
     	pushdown(y);
     }
     if (opt==3)
     {
     	int qq = kth(l);
     	int hj = kth(r+2);
     	splay(qq,0);
     	splay(hj,qq);
     	cout<<mx[ch[hj][0]]<<"\n";
     }
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值