BZOJ1251: 序列终结者

BZOJ1251: 序列终结者

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。
题解Here!
刚开始学Splay时,我也是一脸懵——区间翻转咋整?
然后,我先去做了个更难的题目:BZOJ1500: [NOI2005]维修数列
于是就会做这题了。。。
区间 [ l , r ] 翻转也就是将 l-1 伸展到根,将 r+1 伸展到 l-1 的右子树,然后对 r+1 的左子树,即 [ l , r ] 这段区间打上一个区间翻转标记flag。
下次伸展之前把标记下传一下就好了。
区间加同理。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 50010
#define MAX 2147483647
using namespace std;
int n,m,root,w[MAXN];
struct node{
	int son[2];
	int f,v,s,flag,c;
}a[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void pushup(int rt){
	if(!rt)return;
	a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
	a[rt].v=max(w[rt],max(a[a[rt].son[0]].v,a[a[rt].son[1]].v));
}
inline void pushdown(int rt){
	if(!rt)return;
	if(a[rt].c){
		if(a[rt].son[0]){a[a[rt].son[0]].c+=a[rt].c;a[a[rt].son[0]].v+=a[rt].c;w[a[rt].son[0]]+=a[rt].c;}
		if(a[rt].son[1]){a[a[rt].son[1]].c+=a[rt].c;a[a[rt].son[1]].v+=a[rt].c;w[a[rt].son[1]]+=a[rt].c;}
		a[rt].c=0;
	}
	if(a[rt].flag){
		a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag=0;
		swap(a[rt].son[0],a[rt].son[1]);
	}
}
inline void turn(int rt,int k){
	int x=a[rt].f,y=a[x].f;
	pushdown(x);pushdown(rt);
	a[x].son[!k]=a[rt].son[k];
	if(a[rt].son[k])a[a[rt].son[k]].f=x;
	a[rt].f=y;
	if(y)a[y].son[a[y].son[1]==x]=rt;
	a[x].f=rt;
	a[rt].son[k]=x;
	pushup(x);pushup(rt);
}
void splay(int rt,int ancestry){
	while(a[rt].f!=ancestry){
		int x=a[rt].f,y=a[x].f;
		if(y==ancestry)turn(rt,a[x].son[0]==rt);
		else{
			int k=a[y].son[0]==x?1:0;
			if(a[x].son[k]==rt){turn(rt,!k);turn(rt,k);}
			else{turn(x,k);turn(rt,k);}
		}
	}
	if(ancestry==0)root=rt;
	pushup(rt);
}
int buildtree(int l,int r,int rt){
	if(l>r)return 0;
	int mid;
	if(l==r){
		a[l].f=rt;
		a[l].s=1;
		return l;
	}
	mid=l+r>>1;
	a[mid].son[0]=buildtree(l,mid-1,mid);
	a[mid].son[1]=buildtree(mid+1,r,mid);
	a[mid].f=rt;a[mid].s=1;
	pushup(mid);
	return mid;
}
int kth(int rt,int x){
	pushdown(rt);
	int lsons=0;
	if(a[rt].son[0])lsons=a[a[rt].son[0]].s;
	if(x==lsons+1)return rt;
	if(x<=lsons)return kth(a[rt].son[0],x);
	else return kth(a[rt].son[1],x-lsons-1);
}
int split(int rt,int x,int y){
	int p=kth(rt,x),q=kth(rt,y);
	splay(p,0);splay(q,p);
	return a[q].son[0];
}
void work(int rt,int x,int y,int k){
	int p=kth(rt,x),q=kth(rt,y+2),r;
	splay(p,0);splay(q,p);
	r=a[q].son[0];
	a[r].c+=k;a[r].v+=k;w[r]+=k;
	pushup(q);pushup(p);
}
int main(){
	int f,x,y,k;
	n=read();m=read();
	a[0].v=w[0]=w[1]=w[n+2]=-MAX;
	root=buildtree(1,n+2,0);
	while(m--){
		f=read();x=read();y=read();
		switch(f){
			case 1:{
				k=read();
				work(root,x,y,k);
				break;
			}
			case 2:{
				k=split(root,x,y+2);
				a[k].flag^=1;
				break;
			}
			case 3:{
				k=split(root,x,y+2);
				printf("%d\n",a[k].v);
				break;
			}
		}
	}
	return 0;
}

 

posted @ 2018-07-25 22:44  符拉迪沃斯托克  阅读(185)  评论(0编辑  收藏  举报
Live2D