zoukankan      html  css  js  c++  java
  • 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
    ",seq.tree[1].sum[3]);
                else
                    seq.change(1,lower_bound(pos,pos+p1,num[i])-pos,opr[i]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Id_Name
    注入类型(Injection Type)
    搭建 Spring 2.5.6 开发环境
    模拟Spring框架
    AJAX 学习笔记 2017_05_04
    Gson 转换hibernate级联对象出现StackOverFlow(堆栈溢出)问题
    页面左侧可收缩菜单案例
    struts1.3.10 和 hibernate 3.3.2 一起加载时 出现javax.servlet.ServletException: java.lang.NoSuchMethodError: antlr.collections.A 错误
    1.21 Java基础总结 数组知识
    1.20 Java基础总结 输入数据类型判断 Java低耦合原则 for嵌套思路
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580585.html
Copyright © 2011-2022 走看看