POJ 3468 A simple problem with integers Splay 区间维护模板题

题意:
给你n个数字,m组修改或者询问操作,修改为区间修改,询问也是区间和的询问。
分析:
很简单的一道线段树Lazy练习题,用来练习Splay的区间维护也是一个不错的选择,使用标记来加快速度,最后注意答案要开long long即可Ac
代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn = 100000 + 10;
const int INF = 0x3f3f3f3f;

struct SplayTree {
    int n, root;
    LL Sum[maxn];
    int c[maxn][2], fa[maxn], id[maxn];
    int Val[maxn], Add[maxn], Rank[maxn], size[maxn];

    void init() { 
        n = root = 0;
        memset(c, 0, sizeof(c)); 
        memset(fa, 0, sizeof(fa));
        memset(id, 0, sizeof(id));
        memset(Rank, 0, sizeof(Rank));
    }
    int Newnode(int val, int k) {
        ++n; 
        Val[n] = Sum[n] = val; Add[n] = 0;
        Rank[n] = k; size[n] = 1; id[k] = n;
        return n;
    }
    void Push_up(int u) {
        size[u] = size[c[u][0]] + size[c[u][1]] + 1;
        Sum[u] = Sum[c[u][0]] + Sum[c[u][1]] + Val[u] + Add[u];
    }
    void Push(int u) {
        if(fa[u]) Push(fa[u]);
        Push_down(u);
    } 
    void Push_down(int u) {
        if(Add[u]) {
            Val[u] += Add[u];
            Add[c[u][0]] += Add[u];
            Add[c[u][1]] += Add[u];
            Sum[c[u][0]] += (LL)Add[u] * size[c[u][0]];
            Sum[c[u][1]] += (LL)Add[u] * size[c[u][1]];
        }Add[u] = 0;
    }
    void rotate(int u) {
        int v = fa[u], w = fa[v], t = c[v][1] == u;
        fa[c[u][t^1]] = v, c[v][t] = c[u][t^1]; 
        c[u][t^1] = v; fa[u] = w; fa[v] = u; 

        if(root == v) root = u; 
        else c[w][c[w][1] == v] = u;
        Push_up(v);
    }
    void Splay(int u, int pos) {
        Push(u);
        while(fa[u] != pos) {
            int v = fa[u], w = fa[v];
            if(fa[v] == pos) 
                rotate(u);
            else if((c[v][0] == u) == (c[w][0] == v))  
                rotate(v), rotate(u);
            else 
                rotate(u), rotate(u);
        }Push_up(u);
    }
    void join(int u, int k, int val) {
        int d = k >= Rank[u];
        c[u][d] = Newnode(val, k); fa[n] = u;

        int t = n;
        while(t) {
            Push_up(t);
            t = fa[t];
        }
        Splay(n, 0);
    }
    void insert(int k, int val, int u) {
        int d = k >= Rank[u];
        if(c[u][d]) 
            insert(k, val, c[u][d]);
        else join(u, k, val);
    }
    void update(int u, int v, int w) {
        Splay(id[u-1], 0);
        Splay(id[v+1], root);
        Add[c[id[v+1]][0]] += w;
        Sum[c[id[v+1]][0]] += (LL)size[c[id[v+1]][0]] * w;
    }
    LL query(int x, int y) {
        Splay(id[x-1], 0);
        Splay(id[y+1], root);
        return Sum[c[id[y+1]][0]];
    }
}SPT;

char s[20];
int n, m, u, v, w;

int main() {
#ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    freopen("ans.txt", "w", stdout);
#endif
    scanf("%d%d", &n, &m);

    SPT.root = SPT.Newnode(0, 0);
    for(int i=1; i<=n; i++) {
        scanf("%d", &u);
        SPT.insert(i, u, SPT.root);
    }
    SPT.insert(n+1, 0, SPT.root);

    while(m--) {
        scanf("%s%d%d", s, &u, &v);
        if(s[0] == 'C') {
            scanf("%d", &w);
            SPT.update(u, v, w);
        }else 
            printf("%lld\n", SPT.query(u, v));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值