bzoj1251 序列终结者 平衡树 Splay

bzoj1251: 序列终结者

Description

网上有许多题,就是给定一个序列,要你支持几种操作: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。

Input

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

Output

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

Sample Input

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

Sample Output

2
【数据范围】
N<=50000,M<=100000。、

题解

我没想到居然还有这种裸的Splay
然而还不是WA到死
水题解第一弹

注意一下有负数,我就是因为这个WA了的

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int N = 220000;
const int inf = 0x7fffffff;
int read() {
    char ch = getchar(); int x = 0, f = 1;
    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;
}
int fa[N], ch[N][2], val[N], mx[N], siz[N], add[N], root, sz, n, ans;
bool rev[N];
bool wh(int p) {return ch[fa[p]][1] == p;}
void update(int p) {
    mx[p] = max(max(mx[ch[p][0]], mx[ch[p][1]]), val[p]);
    siz[p] = siz[ch[p][0]] + siz[ch[p][1]] + 1;
}
void Add_tag(int p, int v) {add[p] += v; mx[p] += v; val[p] += v;}
void pushdown(int p) {
    int ls = ch[p][0], rs = ch[p][1];
    if(rev[p]) {
        rev[p] ^= 1; rev[ls] ^= 1; rev[rs] ^= 1;
        swap(ch[p][0], ch[p][1]);
    }
    if(add[p]) {
        if(ls) Add_tag(ls, add[p]);
        if(rs) Add_tag(rs, add[p]);
        add[p] = 0;
    }
}

void print(int p) {
    pushdown(p);
    if(ch[p][0]) print(ch[p][0]);
    cout<<mx[p]<<" ";
    if(ch[p][1]) print(ch[p][1]);
}

void Rotate(int p) {
    int f = fa[p], g = fa[f], c = wh(p);
    if(g) ch[g][wh(f)] = p; fa[p] = g;
    ch[f][c] = ch[p][c ^ 1]; if(ch[f][c]) fa[ch[f][c]] = f;
    ch[p][c ^ 1] = f; fa[f] = p;
    update(f);
}

void Splay(int p, int tar) {
    for(;fa[p] != tar; Rotate(p))
        if(fa[fa[p]] != tar) Rotate(wh(p) == wh(fa[p]) ? fa[p] : p);
    update(p);
    if(!tar) root = p;
}

int Kth(int k) {
    for(int p = root, lsize = 0, cur; p; p = ch[p][k > cur]) {
        pushdown(p); cur = lsize + siz[ch[p][0]];
        if(k == cur + 1) return p;
        if(k > cur) lsize = cur + 1;
    }
    return -1;
}

void Build(int &p, int L, int R, int f) {
    if(!p) p = ++sz;
    fa[p] = f; int mid = L + R >> 1; siz[p] = 1;
    if(mid == 1 || mid == n + 2) val[p] = mx[p] = -inf;
    if(L < mid) Build(ch[p][0], L, mid - 1, p);
    if(R > mid) Build(ch[p][1], mid + 1, R, p);
    update(p);
}

void Addition(int L, int R) {
    int f = Kth(L); Splay(f, 0);
    int p = Kth(R + 2); Splay(p, f);
    Add_tag(ch[p][0], read());
    update(p); update(f);
}

void Rever(int L, int R) {
    int f = Kth(L); Splay(f, 0);
    int p = Kth(R + 2); Splay(p, f);
    rev[ch[p][0]] ^= 1;
}

int Max(int L, int R) {
    int f = Kth(L); Splay(f, 0);
    int p = Kth(R + 2); Splay(p, f); 
    return mx[ch[p][0]];
}

int main() {
    mx[0] = -inf;
    n = read(); int m = read();
    Build(root, 1, n + 2, 0);
    while(m--) {
        int opt = read(), L = read(), R = read();
        if(opt == 1) Addition(L, R);
        if(opt == 2) Rever(L, R);
        if(opt == 3) printf("%d\n", Max(L, R));
    }
    return 0;
}
/*
5 5
1 1 5 -1
1 2 3 -1
2 1 5
3 1 5
3 2 4
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值