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
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output
2
【数据范围】
N<=50000,M<=100000。
【数据范围】
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; }