HDU 4288 Coder 【线段树】

题目链接

segment tree, single-point update

题意

维护一个集合,这个集合可进行以下操作:
+ 向其中添加一个数(保证之前没有这个数)
+ 向其中删除一个数(保证集合中有这个数)
+ 求所有下标%5==3的数的和(从小到大排列)
完成给定的操作,返回sum的值

分析

求区间和问题,尝试使用线段树。然而是求的有步长的和,怎么处理?首先,每个区间中记录下标模5相同的数的和(这个下标是从这个区间的开头开始计数),然后我们考虑线段树中父子结点间的关系:父亲结点中所有下标%5==j的数,一部分也是左子节点中全部%5==j的数,这是显然的;然而对于从右子节点来的那部分,显然因为左子节点中的数,有了一定的偏移,这是我们就要记录偏移量cnt。显然这个偏移量也就是左子节点中的数的个数,所以父亲节点中下标%5==j的数所对应的余数满足关系i=(j+cnt)%5。所以我们可以有不同余数数的和的回溯关系。具体可以见下面代码的pushup部分。
有了这个线段树的基础后,因为x范围太大,所以离线处理,离散化。

AC代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define inputt(x,y) scanf("%d %d",&(x),&(y))
#define bug cout<<"here"<<endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")//stack expansion
//#define debug
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;//1061109567-2147483647
const long long LINF=0x3f3f3f3f3f3f3f3f;//4557430888798830399-9223372036854775807
const int maxn=100000+100;

int N;
int opr[maxn],num[maxn];
int pos[maxn],p1;

void discrete()
{
    sort(pos,pos+p1);
    int t=p1;
    p1=0;
    for(int i=0;i<t;++i)
        if(pos[p1]!=pos[i])
            pos[++p1]=pos[i];
    ++p1;
    return;
}

/* 线段树 */
struct segNode
{
    int left,right;//结点对应的区间端点
    /*结点的性质*/
    int cnt;
    long long sum[5];
};

struct segTree
{
    segNode tree[maxn*4+10];
    /* 由子结点回溯 */
    void Push_Up(int x)
    {
        tree[x].cnt=tree[x<<1].cnt+tree[x<<1|1].cnt;
        for(int i=0;i<5;++i)
        {
            int j=(i+tree[x<<1].cnt)%5;
            tree[x].sum[j]=tree[x<<1].sum[j]+tree[x<<1|1].sum[i];
        }
        return;
    }
    /* 向下更新 */
    /* 线段树构造函数 */
    void build(int x,int left,int right)
    {
        tree[x].left=left;
        tree[x].right=right;
        tree[x].cnt=0;
        cls(tree[x].sum);
        if(left==right)//只有一个元素时
            return;
        /*递归构造子树*/
        int mid=(left+right)>>1;
        build(x<<1,left,mid);
        build(x<<1|1,mid+1,right);
        /* 回溯构造 */
        return;
    }
    /* 单点更新 */
    void change(int x,int p,int v)
    {
        if(tree[x].left==p&&tree[x].right==p)//找到这个点
        {
            if(v)
            {
                tree[x].sum[1]=pos[p];
                ++tree[x].cnt;
            }
            else
            {
                tree[x].sum[1]=0;
                --tree[x].cnt;
            }
            return;
        }
        int mid=(tree[x].left+tree[x].right)>>1;
        if(p<=mid)
            change(x<<1,p,v);
        else
            change(x<<1|1,p,v);
        /* 回溯更新 */
        Push_Up(x);
        return;
    }
}seq;


int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    //IO
    while(input(N)!=EOF)
    {
        char op[10];
        p1=0;
        for(int i=0;i<N;++i)
        {
            scanf("%s",op);
            if(op[0]=='a')
            {
                opr[i]=1;
                input(num[i]);
                pos[p1++]=num[i];
            }
            if(op[0]=='d')
            {
                opr[i]=0;
                input(num[i]);
                pos[p1++]=num[i];
            }
            if(op[0]=='s')
                opr[i]=2;
        }
        discrete();
        seq.build(1,0,p1-1);
        for(int i=0;i<N;++i)
        {
            if(opr[i]==2)
                printf("%lld\n",seq.tree[1].sum[3]);
            else
                seq.change(1,lower_bound(pos,pos+p1,num[i])-pos,opr[i]);
        }
    }
    return 0;
}
posted @ 2016-10-20 21:04  DrCarl  阅读(132)  评论(0编辑  收藏  举报