hdu 4288 Coder

题目链接:点击打开链接


题意:给定一个序列,有三种操作:1.add一个数,把这个数插入到序列中使序列维持递增的位置,2.del一个数,删除这个数,3.sum 查询当前序列中所有位置%5等于3的数的和。


线段树,离线查询+离散化

由于数的范围是10^9,但是只有10^5个数据所以可以离散化。而这就需要统计全部输入中总共出现了多少个数,所以要先将所有命令读入,在以出现过的数的数量建树,离线查询。

线段树每个结点维持5个值,分别存储当前区间中%5=1,2,3,4,5的数的和,这样区间合并方程就是:

void pushup(int rt){
    p[rt].cnt=p[lson].cnt+p[rson].cnt;
    for(int i=0;i<5;i++){
        p[rt].sum[i]=p[lson].sum[i]+p[rson].sum[((i+5-p[lson].cnt)%5+5)%5];
    }
}


离散化用到的两个函数:

unique(a+1,a+N+1)-(a+1)返回a数组中不相等的元素个数

lower_bound(a+1,a+N+1,x) -(a+1)查询a中第一个大于等于x的数的位置下标(从0开始),由于我建树是从1开始,查出的位置要加1


要注意输入数为0的情况,建树时要改成1


代码:

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

#define lson rt<<1
#define rson rt<<1|1
#define MAX 100010
#define ll long long
struct node{
    int l,r;
    ll sum[5];
    int cnt;
}p[MAX<<2];

char oper[MAX][5];
ll a[MAX];
ll b[MAX];
void pushup(int rt){
    p[rt].cnt=p[lson].cnt+p[rson].cnt;
    for(int i=0;i<5;i++){
        p[rt].sum[i]=p[lson].sum[i]+p[rson].sum[((i+5-p[lson].cnt)%5+5)%5];
    }
}

void build(int l,int r,int rt){
    p[rt].l=l;
    p[rt].r=r;
    p[rt].cnt=0;
    for(int i=0;i<5;i++)
        p[rt].sum[i]=0;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(l,m,lson);
    build(m+1,r,rson);
}

void update(int pos,ll v,int rt,int c){
    if(p[rt].l==p[rt].r){
        p[rt].cnt+=c;
        p[rt].sum[0]+=v;
        return ;
    }
    int m=(p[rt].l+p[rt].r)>>1;
    if(m>=pos)update(pos,v,lson,c);
    else update(pos,v,rson,c);
    pushup(rt);
}


int main(){
    int N;
    while(~scanf("%d",&N)){
        int num=0;
        for(int i=1;i<=N;i++){
            scanf("%s",oper[i]);
            if(oper[i][0]!='s'){
                scanf("%I64d",&a[i]);
                b[++num]=a[i];
            }
        }
        sort(b+1,b+num+1);
        num=unique(b+1,b+num+1)-(b+1);
        if(num==0)num=1;
        build(1,num,1);
        for(int i=1;i<=N;i++){
            if(oper[i][0]=='s'){
                printf("%I64d\n",p[1].sum[2]);
                continue;
            }
            else{
                int pos=lower_bound(b+1,b+num+1,a[i])-(b+1);

                if(oper[i][0]=='a')
                update(pos+1,a[i],1,1);
                else update(pos+1,-a[i],1,-1);
            }
        }
    }
    return 0;
}









你可能感兴趣的:(线段树,离散化,离线查询)