BZOJ 1251 序列終結者(Splay)

 

題目大意

 

網上有許多題,就是給定一個序列,要你支持幾種操做: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。php

 

第一行兩個整數 N,M。M 爲操做個數。如下 M 行,每行最多四個整數,依次爲 K, L, R, V。K 表示是第幾種操做,若是不是第 1 種操做則 K 後面只有兩個數。對於每一個第3種操做,給出正確的回答。ios

 

【數據範圍】N<=50000,M<=100000。ide

 

作法分析

 

這題還真不能用 線段樹 作,Splay 是一個不錯的選擇ui

 

對於操做 1 將全部 [L, R] 中的數加上一個常量,能夠對 Splay 樹中的節點增長一個 add 域,表示以該節點爲根中序遍歷所得的數列中每一個數要增長 add,每次執行的時候,先將 L-1 旋轉到根,再把 R+1 旋轉成根的兒子節點,那麼,[L, R] 區間的數列就在 R+1 的左子樹中了,對 R+1 的左兒子執行更新操做便可,相似於線段樹的懶操做spa

對於操做 2 將全部 [L, R] 中的數翻轉,能夠對 Splay 樹中的節點增長一個 rev 域,表示以該節點爲根中序遍歷所得的數列是否須要翻轉,更新的時候仍是和操做 1 同樣,將 L-1 旋轉到根,R+1 旋轉成爲 L-1 的孩子,直接對 R+1 的左兒子更新code

對於操做 3,增長一個 Max 域,表示以該節點爲根中序遍歷獲得的數列中最大值是多少,詢問時,將 L-1 旋轉到根,R+1 旋轉成 L-1 的孩子,詢問 R-1 的左兒子的 Max 便可blog

 

這裏說一點細節:因爲是維護數列,且涉及到區間翻轉操做,因此還要增長一個 Size 域,表示以它爲根的中序遍歷獲得的數列的個數是多少,用它來實現數列中的定位get

因爲涉及到翻轉和統一加權操做,pushDown 和 pushUp 操做必定要想好在哪些地方須要執行string

 

參考代碼

 

 

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 
  5 using namespace std;
  6 
  7 const int N=100005, INF=0x7fffffff;
  8 
  9 struct Splay_Tree {
 10     struct Node {
 11         int val, Max, add, Size, son[2];
 12         bool rev;
 13         void init(int _val) {
 14             val=Max=_val, Size=1;
 15             add=rev=son[0]=son[1]=0;
 16         }
 17     } T[N];
 18     int fa[N], root;
 19 
 20     void pushUp(int x) {
 21         T[x].Max=T[x].val, T[x].Size=1;
 22         if(T[x].son[0]) {
 23             T[x].Max=max(T[x].Max, T[T[x].son[0]].Max);
 24             T[x].Size+=T[T[x].son[0]].Size;
 25         }
 26         if(T[x].son[1]) {
 27             T[x].Max=max(T[x].Max, T[T[x].son[1]].Max);
 28             T[x].Size+=T[T[x].son[1]].Size;
 29         }
 30     }
 31 
 32     void pushDown(int x) {
 33         if(x==0) return;
 34         if(T[x].add) {
 35             if(T[x].son[0]) {
 36                 T[T[x].son[0]].val+=T[x].add;
 37                 T[T[x].son[0]].Max+=T[x].add;
 38                 T[T[x].son[0]].add+=T[x].add;
 39             }
 40             if(T[x].son[1]) {
 41                 T[T[x].son[1]].val+=T[x].add;
 42                 T[T[x].son[1]].Max+=T[x].add;
 43                 T[T[x].son[1]].add+=T[x].add;
 44             }
 45             T[x].add=0;
 46         }
 47         if(T[x].rev) {
 48             if(T[x].son[0]) T[T[x].son[0]].rev^=1;
 49             if(T[x].son[1]) T[T[x].son[1]].rev^=1;
 50             swap(T[x].son[0], T[x].son[1]);
 51             T[x].rev=0;
 52         }
 53     }
 54 
 55     void Rotate(int x, int kind) {
 56         int y=fa[x], z=fa[y];
 57         T[y].son[!kind]=T[x].son[kind], fa[T[x].son[kind]]=y;
 58         T[x].son[kind]=y, fa[y]=x;
 59         T[z].son[T[z].son[1]==y]=x, fa[x]=z;
 60         pushUp(y);
 61     }
 62 
 63     void Splay(int x, int goal) {
 64         if(x==goal) return;
 65         while(fa[x]!=goal) {
 66             int y=fa[x], z=fa[y];
 67             pushDown(z), pushDown(y), pushDown(x);
 68             int rx=T[y].son[0]==x, ry=T[z].son[0]==y;
 69             if(z==goal) Rotate(x, rx);
 70             else {
 71                 if(rx==ry) Rotate(y, ry);
 72                 else Rotate(x, rx);
 73                 Rotate(x, ry);
 74             }
 75         }
 76         pushUp(x);
 77         if(goal==0) root=x;
 78     }
 79 
 80     int Select(int pos) {
 81         int u=root;
 82         pushDown(u);
 83         while(T[T[u].son[0]].Size!=pos) {
 84             if(pos<T[T[u].son[0]].Size) u=T[u].son[0];
 85             else {
 86                 pos-=T[T[u].son[0]].Size+1;
 87                 u=T[u].son[1];
 88             }
 89             pushDown(u);
 90         }
 91         return u;
 92     }
 93 
 94     void update(int L, int R, int val) {
 95         int u=Select(L-1), v=Select(R+1);
 96         Splay(u, 0);
 97         Splay(v, u);
 98         T[T[v].son[0]].Max+=val;
 99         T[T[v].son[0]].val+=val;
100         T[T[v].son[0]].add+=val;
101     }
102 
103     void Reverse(int L, int R) {
104         int u=Select(L-1), v=Select(R+1);
105         Splay(u, 0);
106         Splay(v, u);
107         T[T[v].son[0]].rev^=1;
108     }
109 
110     int query(int L, int R) {
111         int u=Select(L-1), v=Select(R+1);
112         Splay(u, 0);
113         Splay(v, u);
114         return T[T[v].son[0]].Max;
115     }
116 
117     int build(int L, int R) {
118         if(L>R) return 0;
119         if(L==R) return L;
120         int mid=(L+R)>>1, sL, sR;
121         T[mid].son[0]=sL=build(L, mid-1);
122         T[mid].son[1]=sR=build(mid+1, R);
123         fa[sL]=fa[sR]=mid;
124         pushUp(mid);
125         return mid;
126     }
127 
128     void init(int n) {
129         T[0].init(-INF), T[1].init(-INF), T[n+2].init(-INF);
130         for(int i=2; i<=n+1; i++) T[i].init(0);
131         root=build(1, n+2), fa[root]=0;
132         fa[0]=0, T[0].son[1]=root, T[0].Size=0;
133     }
134 };
135 
136 Splay_Tree hehe;
137 
138 int main() {
139     int n, m;
140     scanf("%d%d", &n, &m);
141     hehe.init(n);
142     for(int i=0, a, b, c, d; i<m; i++) {
143         scanf("%d", &a);
144         if(a==1) {
145             scanf("%d%d%d", &b, &c, &d);
146             hehe.update(b, c, d);
147         }
148         else if(a==2) {
149             scanf("%d%d", &b, &c);
150             hehe.Reverse(b, c);
151         }
152         else {
153             scanf("%d%d", &b, &c);
154             printf("%d\n", hehe.query(b, c));
155         }
156     }
157     return 0;
158 }
BZOJ 1251

 

 

題目連接 & AC 通道

 

BZOJ 1251 序列終結者it

相關文章
相關標籤/搜索