bzoj1251 序列终结者(Splay Tree+懒惰标记)
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。
【思路】
Splay Tree+懒惰标记。
用Splay Tree维护序列,添加flip,maxv,addv作为结点信息,其中flip与addv是懒惰标记,需要在Splay中调用pushdown下传标记。对于每次操作,将区间lr分裂出来后执行即可。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 6 const int maxn = 50000+10; 7 const int INF = 1e9; 8 inline int read() { 9 char c=getchar(); 10 while(!isdigit(c)) c=getchar(); 11 int x=0; 12 while(isdigit(c)) { 13 x=x*10+c-'0'; 14 c=getchar(); 15 } 16 return x; 17 } 18 19 struct Node { 20 Node* ch[2]; 21 int v,s,flip,addv,maxv; 22 int cmp(int k) const { 23 int d=k - ch[0]->s; 24 if(d==1) return -1; 25 return d<=0? 0:1; 26 } 27 void pushdown() { 28 if(addv) { 29 v+=addv; 30 ch[0]->addv+=addv,ch[1]->addv+=addv; 31 addv=0; 32 } 33 if(flip) { 34 flip=0; swap(ch[0],ch[1]); ch[0]->flip^=1,ch[1]->flip^=1; 35 } 36 } 37 void maintain() { 38 s=ch[0]->s+ch[1]->s+1; 39 maxv=max(ch[0]->v,ch[1]->v),maxv=max(maxv,v); 40 } 41 }; 42 Node* null=new Node(); 43 void rotate(Node* &o,int d) { 44 Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d],k->ch[d]=o; 45 o->maintain(),k->maintain(); o=k; 46 } 47 void splay(Node* &o,int k) { //splay 的同时pushdown 下传标记 48 o->pushdown(); 49 int d=o->cmp(k); 50 if(d==1) k-=o->ch[0]->s+1; 51 if(d!=-1) { 52 Node* p=o->ch[d]; 53 p->pushdown(); 54 int d2=p->cmp(k); 55 int k2=d2==1? k-p->ch[0]->s-1:k; 56 if(d2!=-1) { 57 splay(p->ch[d2],k2); 58 if(d==d2) rotate(o,d^1); else rotate(o->ch[d],d); 59 } 60 rotate(o,d^1); 61 } 62 } 63 Node* merge(Node* left,Node* right) { 64 splay(left,left->s); 65 left->ch[1]=right,left->maintain(); 66 return left; 67 } 68 void split(Node* o,int k,Node* &left,Node* &right) { 69 splay(o,k); 70 left=o,right=left->ch[1],left->ch[1]=null,left->maintain(); 71 } 72 struct SplaySeq { 73 int n; 74 Node *root,seq[maxn]; 75 Node* build(int sz) { 76 if(!sz) return null; 77 Node* l=build(sz/2); 78 Node* o=&seq[++n]; 79 o->v=0,o->maxv=-INF; 80 o->ch[0]=l,o->ch[1]=build(sz-sz/2-1); 81 o->flip=o->s=0; 82 o->maintain(); 83 return o; 84 } 85 void init(int sz) { 86 n=null->s=null->addv=0; 87 null->v=null->maxv=-INF; 88 root=build(sz); 89 } 90 }ss; 91 92 int n,m; 93 int main() { 94 n=read(),m=read(); 95 ss.init(n+1); 96 int k,l,r,v; 97 Node *left,*right,*mid; 98 for(int i=0;i<m;i++) { 99 k=read(),l=read(),r=read(); 100 split(ss.root,l,left,right),split(right,r-l+1,mid,right); 101 switch(k) { 102 case 1: 103 v=read(); mid->addv+=v; 104 break; 105 case 2: 106 mid->flip^=1; 107 break; 108 case 3: 109 printf("%d\n",mid->maxv); 110 break; 111 } 112 ss.root = merge(merge(left,mid),right); 113 } 114 return 0; 115 }
posted on 2015-12-08 16:18 hahalidaxin 阅读(342) 评论(0) 编辑 收藏 举报