维修数列
【问题描述】
【输入格式】
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
【输出格式】
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
【样例输入】
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
【样例输出】
-1
10
1
10
【数据范围】
题解:
每一个操作都差不多是将通过将左右区间(开区间)端点转到根和右孩子
就能将整个区间转移到根的右孩子的左孩子的子树,就能直接取出信息了
1 #include<cmath> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 const int maxn = 1e6; 9 const int inf = 2e9; 10 inline void Scan(int &x) 11 { 12 char c; 13 bool o = false; 14 while(!isdigit(c = getchar())) o = (c != '-') ? o : true; 15 x = c - '0'; 16 while(isdigit(c = getchar())) x = x * 10 + c - '0'; 17 if(o) x = -x; 18 } 19 int n, m; 20 int num; 21 int root; 22 int deln; 23 int del[maxn]; 24 int id[maxn], pri[maxn]; 25 int lc[maxn], rc[maxn], fat[maxn]; 26 int si[maxn], sum[maxn], val[maxn], lmax[maxn], rmax[maxn], kmax[maxn]; 27 int sam[maxn]; 28 bool rev[maxn]; 29 inline void Update(int x) 30 { 31 int l = lc[x], r = rc[x]; 32 si[x] = si[l] + si[r] + 1; 33 sum[x] = sum[l] + sum[r] + val[x]; 34 lmax[x] = max(lmax[l], sum[l] + val[x] + max(lmax[r], 0)); 35 rmax[x] = max(rmax[r], sum[r] + val[x] + max(rmax[l], 0)); 36 kmax[x] = max(kmax[l], kmax[r]); 37 kmax[x] = max(kmax[x], rmax[l] + lmax[r] + val[x]); 38 kmax[x] = max(kmax[x], max(max(rmax[l], lmax[r]), 0) + val[x]); 39 } 40 inline void Change(int x, int c) 41 { 42 sam[x] = val[x] = c; 43 sum[x] = si[x] * c; 44 kmax[x] = lmax[x] = rmax[x] = c > 0 ? sum[x] : c; 45 } 46 inline void Rever(int x) 47 { 48 rev[x] ^= 1; 49 swap(lmax[x], rmax[x]); 50 swap(lc[x], rc[x]); 51 } 52 inline void Down(int x) 53 { 54 int l = lc[x], r = rc[x]; 55 if(rev[x]) 56 { 57 Rever(l), Rever(r); 58 rev[x] = 0; 59 } 60 if(sam[x] != inf) 61 { 62 Change(l, sam[x]), Change(r, sam[x]); 63 sam[x] = inf; 64 } 65 } 66 inline void Printtree(int k) 67 { 68 if(!k) return; 69 Down(k); 70 printf("k=%d v=%d lc=%d rc=%d si=%d sum=%d ", k, val[k], lc[k], rc[k], si[k], sum[k]); 71 Printtree(lc[k]); 72 Printtree(rc[k]); 73 } 74 void Print(int k) 75 { 76 if(!k) return; 77 Down(k); 78 Print(lc[k]); 79 printf("%d ", val[k]); 80 Print(rc[k]); 81 } 82 inline void Turn(int x) 83 { 84 int y = fat[x], z = fat[y]; 85 int w = (lc[y] != x) ? lc[x] : rc[x]; 86 Down(y), Down(x); 87 fat[y] = x; 88 fat[x] = z; 89 if(w) fat[w] = y; 90 if(z) 91 if(lc[z] == y) lc[z] = x; 92 else rc[z] = x; 93 if(lc[y] == x) rc[x] = y, lc[y] = w; 94 else lc[x] = y, rc[y] = w; 95 Update(y); 96 } 97 inline void Splay(int x, int anc) 98 { 99 Down(x); 100 while(fat[x] != anc) 101 { 102 if(fat[fat[x]] != anc) 103 if((lc[fat[fat[x]]] == fat[x]) == (lc[fat[x]] == x)) Turn(fat[x]); 104 else Turn(x); 105 Turn(x); 106 } 107 Update(x); 108 if(!anc) root = x; 109 } 110 int Build(int l, int r, int f) 111 { 112 int mid = l + r >> 1; 113 int k = id[mid]; 114 fat[k] = f; 115 sam[k] = inf; 116 val[k] = pri[mid]; 117 if(l == r) si[k] = 1; 118 if(l < mid) lc[k] = Build(l, mid - 1, k); 119 if(r > mid) rc[k] = Build(mid + 1, r, k); 120 Update(k); 121 return k; 122 } 123 inline int Find(int x) 124 { 125 int k = root; 126 while(true) 127 { 128 Down(k); 129 int sum = si[lc[k]] + 1; 130 if(sum == x) return k; 131 if(sum > x) k = lc[k]; 132 else k = rc[k], x -= sum; 133 } 134 } 135 inline void Clear(int x) 136 { 137 lc[x] = rc[x] = fat[x] = 0; 138 rev[x] = 0, sam[x] = inf; 139 } 140 inline void Modify(int l, int r, int c) 141 { 142 int x = Find(l), y = Find(r); 143 Splay(x, 0), Splay(y, x); 144 int z = lc[y]; 145 Change(z, c); 146 Update(y), Update(x); 147 } 148 inline void Insert(int l, int r, int n) 149 { 150 int x = Find(l), y = Find(r); 151 Splay(x, 0), Splay(y, x); 152 int cnt = n; 153 while(deln && cnt) id[cnt--] = del[deln--]; 154 while(cnt) id[cnt--] = ++num; 155 int np = Build(1, n, 0); 156 Down(y); 157 lc[y] = np; 158 fat[np] = y; 159 Update(y), Update(x); 160 } 161 void Del(int x) 162 { 163 if(!x) return; 164 Del(lc[x]); 165 del[++deln] = x; 166 Del(rc[x]); 167 Clear(x); 168 } 169 inline void Del(int l, int r) 170 { 171 int x = Find(l), y = Find(r); 172 Splay(x, 0), Splay(y, x); 173 int z = lc[y]; 174 lc[y] = 0; 175 Del(z); 176 Update(y), Update(x); 177 } 178 inline void Reverse(int l, int r) 179 { 180 int x = Find(l), y = Find(r); 181 Splay(x, 0), Splay(y, x); 182 int z = lc[y]; 183 Rever(z); 184 Update(y), Update(x); 185 } 186 inline void Sum(int l, int r) 187 { 188 int x = Find(l), y = Find(r); 189 Splay(x, 0), Splay(y, x); 190 int z = lc[y]; 191 printf("%d ", sum[z]); 192 } 193 inline void Max(int l, int r) 194 { 195 int x = Find(l), y = Find(r); 196 Splay(x, 0), Splay(y, x); 197 int z = lc[y]; 198 printf("%d ", kmax[z]); 199 } 200 char s[233]; 201 int main() 202 { 203 Scan(n), Scan(m); 204 num = n + 2; 205 for(int i = 1; i <= n; ++i) Scan(pri[i + 1]); 206 for(int i = 1; i <= num; ++i) id[i] = i; 207 root = Build(1, num, 0); 208 int pos, tot, c, l, r; 209 while(m--) 210 { 211 scanf("%s", s); 212 switch(s[0]) 213 { 214 case 'I': 215 { 216 Scan(pos), Scan(tot); 217 for(int i = 1; i <= tot; ++i) Scan(pri[i]); 218 Insert(pos + 1, pos + 2, tot); 219 break; 220 } 221 case 'D': 222 { 223 Scan(pos), Scan(tot); 224 Del(pos, pos + tot + 1); 225 break; 226 } 227 case 'R': 228 { 229 Scan(pos), Scan(tot); 230 Reverse(pos, pos + tot + 1); 231 break; 232 } 233 case 'G': 234 { 235 Scan(pos), Scan(tot); 236 Sum(pos, pos + tot + 1); 237 break; 238 } 239 case 'M': 240 { 241 if(s[4] == '-') 242 { 243 Scan(pos), Scan(tot), Scan(c); 244 Modify(pos, pos + tot + 1, c); 245 } 246 else Max(1, si[root]); 247 break; 248 } 249 } 250 } 251 }