【bzoj1895】Pku3580 supermemo Splay
题目描述
给出一个初始序列fA1;A2;:::Ang,要求你编写程序支持如下操作: 1. ADDxyD:给子序列fAx:::Ayg的每个元素都加上D。例如对f1,2, 3,4,5g执行"ADD 241" 会得到f1,3,4,5,5g。 2. REVERSExy:将子序列fAx:::Ayg翻转。例如对f1,2,3,4,5g执 行"REVERSE 24"会得到f1,4,3,2,5g。 3. REVOLVExyT:将子序列fAx:::Ayg旋转T个单位。例如, 对f1,2,3,4,5g执行"REVOLVE 242"会得到f1,3,4,2,5g。 4. INSERTxP:在Ax后插入P。例如,对f1,2,3,4,5g执行"INSERT 24"会得到f1,2,4,3,4,5g。 5. DELETEx:删去Ax。例如,对f1,2,3,4,5g执行"DELETE 2"会得 到f1,3,4,5g。 6. MINxy:查询子序列fAx:::Ayg中的最小元素。例如,对于序列f1, 2,3,4,5g,询问"MIN 24"的返回应为2。
输入
第一行包含一个整数n,表示初始序列的长度。 以下n行每行包含一个整数,描述初始的序列。 接下来一行包含一个整数m,表示操作的数目。 以下m行每行描述一个操作。
输出
对于所有"MIN"操作,输出正确的答案,每行一个。
样例输入
5
1
2
3
4
5
2
ADD 2 4 1
MIN 4 5
样例输出
5
题解
Splay裸题,省选前练习模板的好机会(尽管这次没考。。。)
写一个函数专门用来取出一段区间,可以大大减少代码量。
注意要开long long。
#include <cstdio> #include <cstring> #include <algorithm> #define N 300010 using namespace std; typedef long long ll; int fa[N] , c[2][N] , root , si[N] , rev[N] , tot; ll v[N] , minn[N] , add[N]; char str[20]; void pushup(int k) { si[k] = si[c[0][k]] + si[c[1][k]] + 1; minn[k] = min(v[k] , min(minn[c[0][k]] , minn[c[1][k]])); } void pushdown(int k) { int l = c[0][k] , r = c[1][k]; if(add[k]) { v[l] += add[k] , minn[l] += add[k] , add[l] += add[k]; v[r] += add[k] , minn[r] += add[k] , add[r] += add[k]; add[k] = 0; } if(rev[k]) { swap(c[0][l] , c[1][l]) , rev[l] ^= 1; swap(c[0][r] , c[1][r]) , rev[r] ^= 1; rev[k] = 0; } } void build(int l , int r , int f) { if(l > r) return; int mid = (l + r) >> 1; build(l , mid - 1 , mid) , build(mid + 1 , r , mid); fa[mid] = f , c[mid > f][f] = mid; pushup(mid); } void rotate(int &k , int x) { int y = fa[x] , z = fa[y] , l , r; l = (c[1][y] == x); r = l ^ 1; if(y == k) k = x; else if(c[0][z] == y) c[0][z] = x; else c[1][z] = x; fa[x] = z , fa[y] = x , fa[c[r][x]] = y; c[l][y] = c[r][x] , c[r][x] = y; pushup(y) , pushup(x); } void splay(int &k , int x) { int y , z; while(x != k) { y = fa[x] , z = fa[y]; if(y != k) { if(c[0][y] == x ^ c[0][z] == y) rotate(k , x); else rotate(k , y); } rotate(k , x); } } int find(int k , int x) { pushdown(k); if(x <= si[c[0][k]]) return find(c[0][k] , x); else if(x > si[c[0][k]] + 1) return find(c[1][k] , x - si[c[0][k]] - 1); else return k; } int split(int l , int r) { int a = find(root , l - 1) , b = find(root , r + 1); splay(root , a) , splay(c[1][root] , b); return c[0][c[1][root]]; } void update(int l , int r , int x) { int t = split(l + 1 , r + 1); v[t] += x , minn[t] += x , add[t] += x; pushup(c[1][root]) , pushup(root); } void rever(int l , int r) { int t = split(l + 1 , r + 1); swap(c[0][t] , c[1][t]) , rev[t] ^= 1; } void revol(int l , int r , int x) { x %= r - l + 1; int t = split(r - x + 2 , r + 1); c[0][c[1][root]] = 0 , fa[t] = 0; pushup(c[1][root]) , pushup(root); split(l + 1 , l); c[0][c[1][root]] = t , fa[t] = c[1][root]; pushup(c[1][root]) , pushup(root); } void ins(int p , int x) { split(p + 2 , p + 1); c[0][c[1][root]] = ++tot; fa[tot] = c[1][root]; v[tot] = x; pushup(tot) , pushup(c[1][root]) , pushup(root); } void del(int p) { int t = split(p + 1 , p + 1); c[0][c[1][root]] = 0 , fa[t] = 0; pushup(c[1][root]) , pushup(root); } ll query(int l , int r) { int t = split(l + 1 , r + 1); return minn[t]; } int main() { int n , m , i , x , y , z; ll k; scanf("%d" , &n); v[0] = v[1] = v[n + 2] = minn[0] = 0x3fffffff; for(i = 2 ; i <= n + 1 ; i ++ ) scanf("%d" , &v[i]); build(1 , n + 2 , 0); root = (n + 3) >> 1 , tot = n + 2; scanf("%d" , &m); while(m -- ) { scanf("%s" , str); switch(str[0]) { case 'A': scanf("%d%d%lld" , &x , &y , &k); update(x , y , k); break; case 'I': scanf("%d%d" , &x , &y) , ins(x , y); break; case 'D': scanf("%d" , &x) , del(x); break; case 'M': scanf("%d%d" , &x , &y); printf("%lld\n" , query(x , y)); break; default: { if(str[3] == 'E') scanf("%d%d" , &x , &y) , rever(x , y); else scanf("%d%d%d" , &x , &y , &z) , revol(x , y , z); } } } return 0; }