hdu 4288 线段树 (离散化的离线算法)

输入描述:

输入第一行有一个n 表示接下来有n个命令

接下来的每一行包括一个修改命令 包括一个  字符串命令和一个整数   或者一个求和命令:

  ( 其意思为:  add x  将x插入的数组中,del x 从数组中删除,保持数组有序,保证不插入重复的不删除不存在的

    sum 命令表示输出数组中顺序%5==3 的所有元素之和 )

输出描述: 输出每一个sum命令的结果

输入样例:

9

add 1
add 2
add 3
add 4
add 5
sum
add 6
del 3
sum

输出样例:

3

4

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 100005
struct Seg{
    int lift,right;
    int num;
    long long sum[5];//存放每一段区间中顺序%5的各个值之和
    void init_seg(int l,int r){
        lift=l,right=r,num=0,memset(sum,0,sizeof(sum));
    }
} T[MAXN<<2];
char cmd[MAXN];
int x[MAXN];
int ans[MAXN];
void pushup(int i){//向上修改sum值
    int t1=(i<<1)+1,t2=t1+1;
    for(int j=0; j<5; j++)
        T[i].sum[j]=T[t1].sum[j];
    for(int j=T[t1].num%5,k=0; k<5; k++,j++)
        T[i].sum[j%5]+=T[t2].sum[k];
}
void build(int i,int l,int r){
    T[i].init_seg(l,r);
    if(l==r)
        return;
    build((i<<1)+1,l,((l+r)>>1));
    build((i+1)<<1,((l+r)>>1)+1,r);
}
int key,add_del;//add_del==1 添加一个数 add_del==-1删除一个数
void update(int i){
    if(T[i].lift==T[i].right){
        T[i].num^=1;
        T[i].sum[0]= add_del==1 ? key : 0;
        return;
    }
    if(ans[(T[i].lift+T[i].right)>>1] >= key)
        update((i<<1)+1);
    else
        update((i+1)<<1);
    T[i].num+=add_del;
    pushup(i);
}
int main(){
    int n,top;
    char ch[10];
    while(~scanf("%d",&n)){
        for(int i=top=0; i<n; i++){
            scanf("%s",ch);
            cmd[i]=ch[0];
            if(ch[0]!='s')
                scanf("%d",&x[top]),ans[top]=x[top++];
        }
        sort(ans,ans+top);
        build(0,0,unique(ans,ans+top)-ans-1);
        for(int i=0,j=0; i<n; i++){
            if(cmd[i]=='s'){
                printf("%I64d\n",T[0].sum[2]);
                continue;
            }
            key=x[j++];
            add_del= cmd[i]=='a' ? 1 : -1;
            update(0);
        }
    }
    return 0;
}
posted @ 2012-09-18 15:27  huhanwu  阅读(202)  评论(0编辑  收藏  举报