【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;
}

 

posted @ 2017-04-25 20:46  GXZlegend  阅读(232)  评论(0编辑  收藏  举报