BZOJ1251: 序列终结者

Posted wjyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1251: 序列终结者相关的知识,希望对你有一定的参考价值。

题目大意:维护一种数据结构,支持下列操作:

1.将一个区间加上一个数

2.将一个区间翻转

3.询问一段区间的最大值

感受:傻叉题还敢说自己是序列终结者O__O "…

这道题写的时候还没修改我的splay模板,所以常数较大。。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int read(){
 4   int x=0,f=1;char ch=getchar();
 5   while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();}
 6   while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();}
 7   return x*f;
 8 }
 9 #define N 50005
10 int n,m,root,v[N],fa[N],sz[N],mx[N],tag[N],rev[N],ch[N][2];
11 inline void pushup(int k){
12   int l=ch[k][0],r=ch[k][1];
13   mx[k]=max(mx[l],mx[r]);
14   mx[k]=max(mx[k],v[k]);
15   sz[k]=sz[l]+sz[r]+1;
16 }
17 void pushdown(int k){
18   int l=ch[k][0],r=ch[k][1],t=tag[k];
19   if(t){
20     tag[k]=0;
21     if(l){tag[l]+=t;mx[l]+=t;v[l]+=t;}
22     if(r){tag[r]+=t;mx[r]+=t;v[r]+=t;}
23   }
24   if(rev[k]){
25     rev[k]=0;
26     rev[l]^=1;rev[r]^=1;
27     swap(ch[k][0],ch[k][1]);
28   }
29 }
30 void Pushdown(int x){
31   if(fa[x])Pushdown(fa[x]);
32   pushdown(x);
33 }
34 void rotate(int x,int &beto){
35   int y=fa[x],t=ch[y][1]==x;
36   if(y!=beto)ch[fa[y]][ch[fa[y]][1]==y]=x;else beto=x;
37   fa[x]=fa[y];fa[y]=x;
38   fa[ch[x][!t]]=y;
39   ch[y][t]=ch[x][!t];
40   ch[x][!t]=y;
41   pushup(y);pushup(x);
42 }
43 void splay(int x,int &beto){
44   Pushdown(x);
45   while(x!=beto){
46     int y=fa[x];
47     if(y!=beto){
48       if((ch[fa[y]][1]==y)==(ch[y][1]==x))rotate(y,beto);
49       else rotate(x,beto);
50     }rotate(x,beto);
51   }
52 }
53 void build(int l,int r,int f){
54   int mid=l+r>>1;
55   fa[mid]=f;sz[mid]=1;
56   if(mid<f)ch[f][0]=mid;else ch[f][1]=mid;
57   if(l==r)return;
58   if(l<mid)build(l,mid-1,mid);
59   if(r>mid)build(mid+1,r,mid);
60   pushup(mid);
61 }
62 int find_k(int x,int k){
63   pushdown(x);
64   if(sz[ch[x][0]]==k-1)return x;
65   if(sz[ch[x][0]]<k-1)return find_k(ch[x][1],k-sz[ch[x][0]]-1);
66   return find_k(ch[x][0],k);
67 }
68 int main(){
69   n=read();m=read();n+=2;
70   mx[0]=-1e9;
71   build(1,n,0);root=(1+n)>>1;
72   for(int i=1;i<=m;i++){
73     int t=read(),l=read(),r=read();r+=2;
74     l=find_k(root,l);r=find_k(root,r);
75     splay(l,root);splay(r,ch[l][1]);
76     int z=ch[r][0];
77     if(t==1){
78       int x=read();
79       tag[z]+=x;v[z]+=x;mx[z]+=x;
80     }
81     if(t==2)rev[z]^=1;
82     if(t==3)printf("%d\\n",mx[z]);
83   }
84   return 0;
85 }
86 
View Code

1251: 序列终结者

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 3557  Solved: 1484
[Submit][Status][Discuss]

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。

以上是关于BZOJ1251: 序列终结者的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ1251]序列终结者

BZOJ 1251 序列终结者

[bzoj 1251]序列终结者

BZOJ1251序列终结者 Splay

BZOJ1251: 序列终结者

bzoj1251序列终结者 splay