HDU 4288 Coder (线段树)

本文介绍了一种使用线段树解决包含动态增删元素及特定条件求和的问题的方法。通过对操作离线处理和数值离散化,将增删操作转化为对线段树节点的直接修改,并通过维护节点统计数据实现高效查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意
给你n个操作,分为三种分别是 : add a , del a ,sum,表示的是你可以在添加一个数,删除一个数,求下标 i % 5 == 3 的所有和是多少,注意当你删除一个点的时候,他后面的点的下标都会改变。
思路
由样例可以看出来需要用线段树,具体怎么用?由于线段树没有删除和增加的操作,所以我么把删除和增加离线下来,然后离散一下,把每次操作对应成线段树上的节点,那么每次删除和增加操作我们就可以对节点进行操作,增加就让节点变成他相对应的值,删除就让节点变成0,那么对于求下标i%5 == 3 的和要怎么去求呢?对于每一个节点我们维护两个东西一个是 num,一个是sum[5],num表示的是当前节点所管辖的区间里有多少个值,而sum[5]表示的是当前节点所管辖的区间里的下标%5 = 0,1,2,3,4的值,换句话说就是以当前节点开始的第1个值,第2个值…当前节点就是区间的第一个值,那么对于pushup来说,他的sum[i]的值其实就是左区间的sum[i]加上右区间sum[((i-sum左区间的有效数目)%5 + 5 ) % 5],仔细想想,如果你要区间合并的时候,左区间有3个数,那么你右区间的第一个数应该是4,而不是1,对吧。这样就好了,其实这题的难点就在于区间合并的时候,如何把右区间的第i个值是全区间的第几个值。
代码

#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn = 1e5+100;
char sh[maxn][10] ;
long long x[maxn] , a[maxn];    
int cnt = 0;
struct Segtree
{
    long long num[maxn<<2];
    long long sum[maxn<<2][5];
    void pushup(int rt)
    {
        for(int i = 0 ; i < 5 ; i++)
        {
            sum[rt][i] = sum[rt<<1][i] + sum[rt<<1|1][((i - num[rt<<1])%5 + 5)%5];
        }
    }
    void build(int l,int r,int rt)
    {
        memset(sum[rt],0,sizeof(sum[rt]));
        num[rt] = 0; 
        if(l == r) return ;
        int m = (l+r)>>1;
        build(lson);
        build(rson);
    }
    void update(int pos,long long val,int op,int l,int r,int rt)
    {
        op ? ++num[rt]:--num[rt];
        if(l == r)
        {
            sum[rt][0] = val * op;
            return ;
        }
        int m = (l+r)>>1;
        if(pos <= m) update(pos,val,op,lson);
        else update(pos,val,op,rson);
        pushup(rt);
    }
}tree;

int main()
{

    long long n;
    while(scanf("%lld",&n)!=EOF)
    {
        cnt = 0;
        for(int i = 0 ; i < n ;i++)
        {
            cin>>sh[i];
            if(sh[i][0] != 's')
            {
                scanf("%lld",&a[i]);
                x[cnt++] = a[i];
            }
        }
        sort(x,x+cnt);
        cnt = unique(x,x+cnt) - x;
        tree.build(1,cnt,1);
        for(int i = 0 ; i < n ;i++)
        {
            if(sh[i][0] == 'a')
            {
                int k = lower_bound(x,x+cnt,a[i]) - x + 1;
                tree.update(k,a[i],1,1,cnt,1);
            }
            else if(sh[i][0] == 'd')
            {
                int k = lower_bound(x,x+cnt,a[i]) - x + 1;
                tree.update(k,a[i],0,1,cnt,1);
            }
            else  printf("%lld\n",tree.sum[1][2]);
        }
        //print(1,cnt,1);
    }
    return 0;


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值