HDU 4288 Coder

题意: 有连续 n 个操作,一开始集合为空,对应有三种操作:

         add x    : 如果x 不在集合中,加入 x 到集合中

         del  x    : 如果x 在集合中,删除之

         sum      : 集合中存在的数排好序之后输出满足 序号%5=3 的数值的和    

分析: 每个区间维护两个数组

         num[i]    i 区间内部不同数值的个数

         s[i][5]    i 区间内部数值序号对 5 取模后各种情况的和

#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
using namespace std;
#define maxn 100005
#define clr(x)memset(x,0,sizeof(x))
__int64 s[maxn<<2][5];
__int64 val[maxn];
int num[maxn<<2];
map<long long,int>v1; 
map<long long,int>v2;
void creat(int l,int r,int rt)
{
    int i;
    for(i=0;i<5;i++)
        s[rt][i]=0;
    num[rt]=0;
    if(l==r)
    {
        v1[val[l]]=l;      // 记录每个排好序的数值所在叶子区间,方便插入和删除
        return;
    }
    int mid=(l+r)>>1;
    creat(l,mid,rt<<1);
    creat(mid+1,r,rt<<1|1);
}
void add(int x,int l,int r,int rt)
{
    if(l==r)               // 找到了区间端点为 x 的位置
    {
        num[rt]=1;
        s[rt][1]=val[x];   // 只有一个数,所以该区间的第一个数即为插入的数值
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        add(x,l,mid,rt<<1);
    else add(x,mid+1,r,rt<<1|1);
    int i;
    for(i=0;i<5;i++)                   // 先累加左子树对5取模各种情况的数值的和到根区间
        s[rt][i]=s[rt<<1][i];
    int t=num[rt<<1];                  // 左子树数值的个数
    for(i=0;i<5;i++)              
        s[rt][(i+t)%5]+=s[rt<<1|1][i]; // 累加右子树对5取模各种情况的数值的和到根区间
    num[rt]=num[rt<<1]+num[rt<<1|1];   // 累加左子树和右子树在集合中数的个数
}
void del(int x,int l,int r,int rt)     // 删除操作和插入类似
{
    if(l==r)
    {
        num[rt]=0;
        s[rt][1]=0;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        del(x,l,mid,rt<<1);
    else
        del(x,mid+1,r,rt<<1|1);
    int i;
    for(i=0;i<5;i++)
        s[rt][i]=s[rt<<1][i];
    int t=num[rt<<1];
    for(i=0;i<5;i++)
        s[rt][(i+t)%5]+=s[rt<<1|1][i];
    num[rt]=num[rt<<1]+num[rt<<1|1];
}
char op[5];
__int64 a[maxn];
int id[maxn];
int main()
{
    int i,n,tot;
    while(scanf("%d",&n)!=EOF)
    {
        tot=0;
        for(i=1;i<=n;i++)           // 离线按顺序保存操作
        {  
            scanf("%s",op);
            if(op[0]=='a')
            {
                scanf("%I64d",&a[i]);
                id[i]=1;
                val[++tot]=a[i];    // 记录所有可能加入集合的数值
            }
            else if(op[0]=='d')
            {
                scanf("%I64d",&a[i]);
                id[i]=2;
            }
            else
                id[i]=3;
        }
        v1.clear();
        v2.clear();
        sort(val+1,val+1+tot);    // 排序好可能加入的数值,离散化
        creat(1,tot,1);           
        for(i=1;i<=n;i++)
        {
            if(id[i]==1)
            {
                if(v2[a[i]]==0)   // 如果集合中没有
                {
                    v2[a[i]]=1;
                    add(v1[a[i]],1,tot,1);
                }
            }
            else if(id[i]==2)
            {
                if(v2[a[i]]==1) // 如果集合中存在
                {
                    v2[a[i]]=0;
                    del(v1[a[i]],1,tot,1);
                }
            }
            else printf("%I64d\n",s[1][3]);
        }
    }
    return 0;
}

 


 

posted @ 2012-09-18 08:37  'wind  阅读(162)  评论(0编辑  收藏  举报