POJ 3468 Splay 解法

题解

Splay入门模板
将l - 1移到根, r + 1移到根下方, 那么[l, r]就在根的右子树的左子树上, 更新的时候也这样旋转, 更新lazy


code:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define debug 0
#define M(a, b) memset(a, b, sizeof(a))
#define ls ch[x][0]
#define rs ch[x][1]
const int maxn = (1e5 + 10);

struct Splay{
    int pre[maxn], ch[maxn][2], sz[maxn], v[maxn];
    int add[maxn], a[maxn];
    int root, rt;
    long long sum[maxn];

    Splay() {
        root = rt = 0;
        M(pre, 0);
        M(ch, 0);
        M(sz, 0);
        M(v, 0);
        M(sum, 0);
        M(add, 0);
    }

    void newNode(int &x, int c) {//新建节点
        x = ++rt;
        sz[x] = 1;
        v[x] = sum[x] = c;
    }

    void pushDown(int x) {//下移
        if (add[x]) {
            v[x] += add[x];
            add[ls] += add[x];
            add[rs] += add[x];
            sum[ls] += (long long)sz[ls] * add[x];
            sum[rs] += (long long )sz[rs] * add[x];
            add[x] = 0;
        }
    }

    void pushUp(int x) {//向上传递
        sz[x] = sz[ls] + sz[rs] + 1;
        sum[x] = sum[ls] + sum[rs] + v[x];
    }

    void Rotate(int x, int d) {//旋转
        int y = pre[x];
        pushDown(y);
        pushDown(x);
        ch[y][!d] = ch[x][d];
        pre[ch[y][!d]] = y;

        pre[x] = pre[y];
        ch[x][d] = y;

        if (pre[y]) ch[pre[y]][ch[pre[y]][1] == y] = x;
        pre[y] = x;

        pushUp(y);
    }

    void splay(int x, int to) {//转到

        while (pre[x] != to) {
            if (pre[pre[x]] == to) Rotate(x, ch[pre[x]][0] == x);
            else {
                int y = pre[x], z = pre[y];
                int f = (ch[z][1] == y);
                if (ch[y][f] == x)
                    Rotate(y, !f), Rotate(x, !f);
                else
                    Rotate(x, f), Rotate(x, !f);
            }
        }

        pushUp(x);
        if (!to) root = x;
    }

    void RotateTo(int k, int to) {
        int x = root;
        pushDown(x);

        while (sz[ls] != k) {
            if (sz[ls] < k) {
                k -= sz[ls] + 1;
                x = rs;
            }
            else {
                x = ls;
            }
            pushDown(x);//要旋转在查找时要下移
        }

        splay(x, to);
    }

    void build(int &x, int l, int r, int f) {
        if (l > r) return;

        int mid = (l + r) >> 1;
        newNode(x, a[mid]);

        build(ls, l, mid - 1, x);
        build(rs, mid + 1, r, x);
        pre[x] = f;
        pushUp(x);
    }

    void init(int n) {
        newNode(root, -1);//加两个节点, 去除冗余信息
        newNode(ch[root][1], -1);

        pre[rt] = root;
        sz[root] = 2;

        for (int i = 0; i < n; ++i) scanf("%d", &a[i]);

        build(ch[ch[root][1]][0], 0, n - 1, ch[root][1]);//建树, 保证中序遍历一致

        pushUp(ch[root][1]);//传递
        pushUp(root);
    }

    void update(int l, int r, int val) {
        RotateTo(l - 1, 0);
        RotateTo(r + 1, root);
        add[ch[ch[root][1]][0]] += val;
        sum[ch[ch[root][1]][0]] += (long long )val * sz[ch[ch[root][1]][0]];//[l, r]lazy
    }

    long long query(int l, int r) {
        RotateTo(l - 1, 0);
        RotateTo(r + 1, root);
        return sum[ch[ch[root][1]][0]];
    }
}sp;
int main() {

#if debug
    freopen("in.txt", "r", stdin);
#endif //debug

    //cin.tie(0);
    //cin.sync_with_stdio(false);

    int n, m, l, r, c;
    char s[5];

    while (~scanf("%d%d", &n, &m)) {

        sp.init(n);

        while (m--) {
            scanf("%s%d%d", s, &l, &r);
            if (s[0] == 'Q') printf("%I64d\n", sp.query(l, r));
            else {
                scanf("%d", &c);
                sp.update(l, r, c);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值