A - Coder HDU - 4288——线段树

本文探讨了如何使用线段树来维护有序集合,包括插入、删除和求和操作。通过预处理线段树节点的关系实现高效建树,并提供了一道HDU 4288的解题思路和Accepted代码。
摘要由CSDN通过智能技术生成

Think:
1知识点:预处理得到有序线段树结点对应关系进而逐渐建树
2题意:维护有序集合的插入操作/删除操作/求和操作

vjudge题目链接

以下为Accepted代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1e5 + 4e2;

struct Tree{
    int cnt;
    LL sum[5];
}tree[N<<2];

int data[N], tmp[N];
char st[N][14];

void Pushup(int rt);/*更新rt结点*/
void Build(int l, int r, int rt);/*逐渐建立有序线段树*/
void Updata(int flag, int p, int v, int l, int r, int rt);/*有序线段树的增加和删除操作*/

int main(){
    int n, i, num;
    while(~scanf("%d", &n)){
        num = 0;
        for(i = 0; i < n; i++){
            scanf("%s", st[i]);
            if(st[i][0] != 's'){
                scanf("%d", &data[i]);
                tmp[num++] = data[i];
            }
        }
        sort(tmp, tmp+num);
        num = unique(tmp, tmp+num) - tmp;/*预处理得到有序建树结点*/

        Build(1, num, 1);
        for(i = 0; i < n; i++){
            int p = lower_bound(tmp, tmp+num, data[i]) - tmp;/*查找得到当前结点应在有序线段树结点中的位置*/
            if(st[i][0] == 's')
                printf("%lld\n", tree[1].sum[2]);/*tree[1].sum[2]:记录了当前有序线段树中()%5=2的和*/
            else if(st[i][0] == 'a')
                Updata(1, p, data[i], 1, num, 1);/*将当前结点增加到有序线段树中应插入的位置*/
            else
                Updata(-1, p, 0, 1, num, 1);/*将当前结点从有序线段树中删除*/
        }
    }
    return 0;
}
void Build(int l, int r, int rt){/*更新rt结点*/
    memset(tree[rt].sum, 0, sizeof(tree[rt].sum));
    tree[rt].cnt = 0;
    if(l == r) return;
    int mid = (l+r)/2;
    Build(l, mid, rt<<1);
    Build(mid+1, r, rt<<1|1);
}
void Updata(int flag, int p, int v, int l, int r, int rt){/*逐渐建立有序线段树*/
    if(l == r){
        tree[rt].cnt += flag;/*flag = 1表示增加一个结点;flag = -1表示删除一个结点*/
        tree[rt].sum[0] = v;/*初始增加到0上则查询时输出tree[1].sum[2]*/
        return;
    }
    int mid = (l+r)/2;
    if(p <= mid)
        Updata(flag, p, v, l, mid, rt<<1);
    else
        Updata(flag, p, v, mid+1, r, rt<<1|1);
    Pushup(rt);
}
void Pushup(int rt){/*有序线段树的增加和删除操作*/
    for(int i = 0; i < 5; i++){
        tree[rt].sum[i] = tree[rt<<1].sum[i] + tree[rt<<1|1].sum[((i-tree[rt<<1].cnt)%5+5)%5];/*通过右子树已增加的有序结点个数得到左子树当前状态应对应的sum下标*/
    }
    tree[rt].cnt = tree[rt<<1].cnt + tree[rt<<1|1].cnt;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值