1. 程式人生 > >1251. 序列終結者【平衡樹-splay】

1251. 序列終結者【平衡樹-splay】

gpo name blog swap push cpp turn AC ace

Description

網上有許多題,就是給定一個序列,要你支持幾種操作:A、B、C、D。一看另一道題,又是一個序列 要支持幾種操作:D、C、B、A。尤其是我們這裏的某人,出模擬試題,居然還出了一道這樣的,真是沒技術含量……這樣 我也出一道題,我出這一道的目的是為了讓大家以後做這種題目有一個“庫”可以依靠,沒有什麽其他的意思。這道題目 就叫序列終結者吧。 【問題描述】 給定一個長度為N的序列,每個序列的元素是一個整數(廢話)。要支持以下三種操作: 1. 將[L,R]這個區間內的所有數加上V。 2. 將[L,R]這個區間翻轉,比如1 2 3 4變成4 3 2 1。 3. 求[L,R]這個區間中的最大值。 最開始所有元素都是0。

Input

第一行兩個整數N,M。M為操作個數。 以下M行,每行最多四個整數,依次為K,L,R,V。K表示是第幾種操作,如果不是第1種操作則K後面只有兩個數。

Output

對於每個第3種操作,給出正確的回答。

Sample Input

4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4

Sample Output

2
【數據範圍】
N<=50000,M<=100000。

splay區間操作模板

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#define MAXN (1000000+10)
using namespace std;
int Father[MAXN];
int Son[MAXN][2];
int Key[MAXN];
int Size[MAXN];
int Root,sz,n,m;
int Max[MAXN],Val[MAXN],Add[MAXN],Rev[MAXN];
using namespace std;

inline int Get(int x)
{
	return Son[Father[x]][1]==x;
}

inline void Update(int x)
{
	Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;
	Max[x]=max(Val[x],max(Max[Son[x][0]],Max[Son[x][1]]));
}

inline void Pushdown(int x)
{
	if (Add[x])
	{
		if (Son[x][0])
		{
			Max[Son[x][0]]+=Add[x];
			Val[Son[x][0]]+=Add[x];
			Add[Son[x][0]]+=Add[x];
		}
		if (Son[x][1])
		{
			Max[Son[x][1]]+=Add[x];
			Val[Son[x][1]]+=Add[x];
			Add[Son[x][1]]+=Add[x];
		}
		Add[x]=0;
	}
	if (Rev[x])
	{
		Rev[x]=0;
		swap(Son[x][0],Son[x][1]);
		Rev[Son[x][0]]^=1;
		Rev[Son[x][1]]^=1;	
	}
}

inline void Rotate(int x)
{
	Pushdown(Father[x]);
	Pushdown(x);
	int wh=Get(x);
	int fa=Father[x],fafa=Father[fa];
	Son[fa][wh]=Son[x][wh^1];
	Father[fa]=x;
	if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
	Son[x][wh^1]=fa;
	Father[x]=fafa;
	if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
	Update(fa);
	Update(x);
}

inline void Splay(int x,int tar)
{
	for (int fa;(fa=Father[x])!=tar;Rotate(x))
		if (Father[fa]!=tar)
			Rotate(Get(fa)==Get(x)?fa:x);
	if (!tar) Root=x;
}

void Build(int l,int r,int fa)
{
	if (l>r) return;
	if (l==r)
	{
		Size[l]=1;
		Father[l]=fa;
		Son[fa][l>fa]=l;
		return;
	}
	int mid=(l+r)>>1;
	Build(l,mid-1,mid);
	Build(mid+1,r,mid);
	Father[mid]=fa;
	Son[fa][mid>fa]=mid;
	Update(mid);
}

int Findx(int x)
{
	int now=Root;
	while (1)
	{
		Pushdown(now);
		if (Size[Son[now][0]]>=x)
			now=Son[now][0];
		else
		{
			x-=Size[Son[now][0]];
			if (x==1)
			{
				Splay(now,0);
				return now;
			}
			x--;
			now=Son[now][1];
		}
	}
}

inline int Split(int x,int y)
{
	int xx=Findx(x),yy=Findx(y);
	Splay(xx,0);
	Splay(yy,xx);
	return Son[yy][0];
}

int main()
{
	int p,l,r,x;
	scanf("%d%d",&n,&m);
	Build(1,n+2,0);
	Root=(n+3)>>1;
	Max[0]=-0x7fffffff;
	for (int i=1;i<=m;++i)
	{
		scanf("%d",&p);
		if (p==1)
		{
			scanf("%d%d%d",&l,&r,&x);
			int node=Split(l,r+2);
			Val[node]+=x; 
			Max[node]+=x; 
			Add[node]+=x;
		}
		if (p==2)
		{
			scanf("%d%d",&l,&r);
			int node=Split(l,r+2);
			Rev[node]^=1;
		}
		if (p==3)
		{
			scanf("%d%d",&l,&r);
			int node=Split(l,r+2);
			printf("%d\n",Max[node]);
		}
	}
}

1251. 序列終結者【平衡樹-splay】