【BZOJ 1251】 序列终结者

1251: 序列终结者

Time Limit: 20 Sec   Memory Limit: 162 MB
Submit: 2396   Solved: 952
[ Submit][ Status]

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。

HINT

Source

以位置为关键字的splay模板题。


做了BZOJ1500后这道就轻而易举了,此题同BZOJ1500一样要注意zigzag的Push_down问题

(详见BZOJ1500


#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#define maxx 10000000
using namespace std;
struct splay
{
	int l,r,fa,data,rev,add,maxv,size;
}a[500005];
int tot=0,root=0,f[500005],m,n;
void Push_down(int x)
{
	if (!x) return;
	if (a[x].add!=0)
	{
		a[a[x].l].add+=a[x].add,a[a[x].r].add+=a[x].add;
		a[x].maxv+=a[x].add;
		a[x].data+=a[x].add;
		a[x].add=0;
	}
	if (a[x].rev)
	{
		swap(a[x].l,a[x].r);
		a[x].rev=0;
		a[a[x].l].rev^=1;
		a[a[x].r].rev^=1;
	}
}
void Push_up(int x)
{
	if (!x) return;
	a[x].size=a[a[x].l].size+a[a[x].r].size+1;
	if (a[a[x].l].maxv>a[a[x].r].maxv) a[x].maxv=a[a[x].l].maxv;
	else a[x].maxv=a[a[x].r].maxv;
	if (a[x].data>a[x].maxv) a[x].maxv=a[x].data;
}
void New_node(int &x,int fa,int v)
{
	x=++tot;
	a[x].fa=fa;
	a[x].data=v;
	a[x].rev=a[x].add=a[x].l=a[x].r=0;
	a[x].maxv=v;
}
void Build(int &x,int fa,int l,int r)
{
	if (l>r) return;
	int m=(l+r)>>1;
	New_node(x,fa,f[m]);
	Build(a[x].l,x,l,m-1);
	Build(a[x].r,x,m+1,r);
	Push_up(x);
}
void zig(int x)
{
	int y=a[x].fa;
	int z=a[y].fa;
	Push_down(a[y].r),Push_down(a[x].l),Push_down(a[x].r);
	a[y].fa=x,a[x].fa=z;
	a[y].l=a[x].r,a[a[x].r].fa=y,a[x].r=y;
	if (y==a[z].l) a[z].l=x;
	else a[z].r=x;
	Push_up(y);
}
void zag(int x)
{
	int y=a[x].fa;
	int z=a[y].fa;
	Push_down(a[y].l),Push_down(a[x].l),Push_down(a[x].r);
	a[y].fa=x,a[x].fa=z;
	a[y].r=a[x].l,a[a[x].l].fa=y,a[x].l=y;
	if (y==a[z].l) a[z].l=x;
	else a[z].r=x;
	Push_up(y);
}
void splay(int x,int s)
{
	Push_down(x);
	while (a[x].fa!=s)
	{
		int y=a[x].fa;
		int z=a[y].fa;
		if (z==s)
		{
			if (x==a[y].l) zig(x);
			else zag(x);
			break;
		}
		if (y==a[z].l)
		{
			if (x==a[y].l) zig(y),zig(x);
			else zag(x),zig(x);
		}
		else
		{
			if (x==a[y].r) zag(y),zag(x);
			else zig(x),zag(x);
		}
	}
	Push_up(x);
	if (s==0) root=x;
}
int Findkth(int x,int k)
{
	Push_down(x);
	int s=a[a[x].l].size;
	if (k==s+1) return x;
	if (k<=s) return Findkth(a[x].l,k);
	return Findkth(a[x].r,k-s-1);
}
void Add(int l,int r,int v)
{
	int x=Findkth(root,l);
	splay(x,0);
	x=Findkth(root,r+2);
	splay(x,root);
	int y=a[x].l;
	a[y].add+=v;
	splay(y,0);
}
void Reverse(int l,int r)
{	
	int x=Findkth(root,l);
	splay(x,0);
	x=Findkth(root,r+2);
	splay(x,root);
	int y=a[x].l;
        a[y].rev^=1;
	splay(y,0);
}
int Findmax(int l,int r)
{	
	int x=Findkth(root,l);
	splay(x,0);
	x=Findkth(root,r+2);
	splay(x,root);
	int y=a[x].l;
	Push_down(y);
        return a[y].maxv;
}
int main()
{
	scanf("%d%d",&n,&m);
	f[1]=f[2]=-maxx;
	a[0].maxv=-maxx;
	Build(root,0,1,2);
	for (int i=1;i<=n;i++)
		f[i]=0;
	Build(a[2].l,2,1,n);
	while (m--)
	{
		int k,l,r,v;
		scanf("%d%d%d",&k,&l,&r);
		if (k==1)
		{
			scanf("%d",&v);
			Add(l,r,v);
		}
		else if (k==2)
		{
			Reverse(l,r);
		}
		else printf("%d\n",Findmax(l,r));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值