【bzoj1251】序列终结者 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。

输入

第一行两个整数N,M。M为操作个数。 以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。

输出

对于每个第3种操作,给出正确的回答。

样例输入

4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4

样例输出

2


题解

Splay模板题。

然而数组开到50001无故TLE调了1个小时QAQ

由于有哨兵节点,所以开数组时要比平常多2,也就是至少要开到50003!

下次再也不擦边开数组了。。。

#include <cstdio>
#include <algorithm>
using namespace std;
int num[50005] , c[2][50005] , fa[50005] , add[50005] , rev[50005] , maxn[50005] , si[50005] , root;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
void pushup(int k)
{
    int l = c[0][k] , r = c[1][k];
    maxn[k] = max(num[k] , max(maxn[l] , maxn[r]));
    si[k] = si[l] + si[r] + 1;
}
void pushdown(int k)
{
    int l = c[0][k] , r = c[1][k];
    if(add[k])
    {
        if(l) num[l] += add[k] , maxn[l] += add[k] , add[l] += add[k];
        if(r) num[r] += add[k] , maxn[r] += add[k] , add[r] += add[k];
        add[k] = 0;
    }
    if(rev[k])
    {
        if(l) swap(c[0][l] , c[1][l]) , rev[l] ^= 1;
        if(r) 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;
    pushup(mid);
    c[mid > f][f] = mid;
}
void rotate(int &k , int x)
{
    int y = fa[x] , z = fa[y] , l , r;
    l = (c[0][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)
{
    while(x != k)
    {
        int 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 r)
{
    pushdown(k);
    if(r <= si[c[0][k]]) return find(c[0][k] , r);
    else if(r > si[c[0][k]] + 1) return find(c[1][k] , r - si[c[0][k]] - 1);
    else return k;
}
void update(int l , int r , int v)
{
    int lp = find(root , l) , rp = find(root , r + 2) , z;
    splay(root , lp);
    splay(c[1][root] , rp);
    z = c[0][rp];
    num[z] += v;
    maxn[z] += v;
    add[z] += v;
}
void rever(int l , int r)
{
    int lp = find(root , l) , rp = find(root , r + 2) , z;
    splay(root , lp);
    splay(c[1][root] , rp);
    z = c[0][rp];
    swap(c[0][z] , c[1][z]);
    rev[z] ^= 1;
}
int query(int l , int r)
{
    int lp = find(root , l) , rp = find(root , r + 2) , z;
    splay(root , lp);
    splay(c[1][root] , rp);
    z = c[0][rp];
    return maxn[z];
}
int main()
{
    int n , m , k , l , r , v;
    maxn[0] = 0x80000000;
    n = read() , m = read();
    build(1 , n + 2 , 0);
    root = (n + 3) >> 1;
    while(m -- )
    {
        k = read() , l = read() , r = read();
        switch(k)
        {
            case 1: v = read(); update(l , r , v); break;
            case 2: rever(l , r); break;
            default: printf("%d\n" , query(l , r));
        }
    }
    return 0;
}
posted @ 2017-02-15 10:54  GXZlegend  阅读(330)  评论(0编辑  收藏  举报