• HDU 4348 To the moon 【主席树+区间修改】


    persistent segment tree
    题目链接

    题意

    给一串初始序列An,并且初始的时间是0,定义以下操作:
    1. 给一个区间内的数加上一个值,并且时间加一
    2. 查询当前某区间的区间和
    3. 查询过去某个时间的某个区间和
    4. 回到某个时间

    序列大小和查询数量级为1e5

    分析

    SPOJ上也有这个题,但HDU卡内存严格一些,所以有些方法就不能过了。
    首先既然有历史版本,那么就用主席树吧。这里主席树中更新的一个版本就是上一个版本的线段树进行一次区间修改。平常写线段树遇到区间修改一般是要用lazytag存一下每个整个结点的变化量,然后有需要访问子结点时再pushdown下来。但是,如果在主席树中仿照这样做,每需要访问子结点都pushdown一下并建立新节点的话,肯定会爆内存的,因为极端情况下,这样的主席树最终就会变成n棵线段树。
    其实关于区间修改的线段树还有另一种写法:同样记录lazytag,但不pushdown,而是在每次查询的时候记录当前查询链中的遇到的所有lazytag的和,最终加在那个末尾的查询结点的返回值上。线段树中这两种写法其实是没有太大的效果差异的,但在主席树中就不同了,显然后者在遇到中间结点更改时,之后的访问不需要新增子结点,从而大大减少空间消耗。

    AC代码

    //HDU 4348 To the moon
    //AC 2016-11-15 17:39:11
    //persistent segment tree
    #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,m;
    long long A[maxn];
    
    struct chairmanTree
    {
        struct chairNode
        {
            long long sum;
            int lazy;
            int ls,rs;
        }tree[maxn*80];
        int root[maxn];
        size_t tsize;
        void setup()
        {
            tsize=1;
            root[0]=0;
            tree[0].ls=tree[0].rs=tree[0].sum=tree[0].lazy=0;
            return;
        }
        void update(int c,int s,int t,int L,int R,int d)
        {
            root[c]=insert(root[c-1],s,t,L,R,d);
            return;
        }
        int insert(int x,int s,int t,int L,int R,int d)
        {
            tree[tsize++]=tree[x];
            x=tsize-1;
            tree[x].sum+=d*1LL*(t-s+1);
            if(s==L&&t==R)
            {
                tree[x].lazy+=d;
                return x;
            }
            int mid=(L+R)>>1;
            if(t<=mid)
                tree[x].ls=insert(tree[x].ls,s,t,L,mid,d);
            else if(s>mid)
                tree[x].rs=insert(tree[x].rs,s,t,mid+1,R,d);
            else
            {
                tree[x].ls=insert(tree[x].ls,s,mid,L,mid,d);
                tree[x].rs=insert(tree[x].rs,mid+1,t,mid+1,R,d);
            }
            return x;
        }
        long long querry(int x,int s,int t,int L,int R,int tag)
        {
            if(s==L&&t==R)
                return tree[x].sum+(R-L+1)*1LL*tag;
            int mid=(L+R)>>1;
            if(t<=mid)
                return querry(tree[x].ls,s,t,L,mid,tag+tree[x].lazy);
            else if(s>=mid+1)
                return querry(tree[x].rs,s,t,mid+1,R,tag+tree[x].lazy);
            else
                return querry(tree[x].ls,s,mid,L,mid,tag+tree[x].lazy)+querry(tree[x].rs,mid+1,t,mid+1,R,tag+tree[x].lazy);
        }
    }cT;
    
    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
        bool first=1;
        while(inputt(n,m)!=EOF)
        {
            if(!first) putchar('
    ');
            first=0;
            for(int i=1;i<=n;++i)
            {
                scanf("%lld",&A[i]);
                A[i]+=A[i-1];
            }
            cT.setup();
            char opr[2];
            int a,b,c;
            int cur=0;
            while(m--)
            {
                scanf("%s",opr);
                if(opr[0]=='C')
                {
                    inputt(a,b);input(c);
                    ++cur;
                    cT.update(cur,a,b,1,n,c);
                }
                if(opr[0]=='Q')
                {
                    inputt(a,b);
                    printf("%lld
    ",cT.querry(cT.root[cur],a,b,1,n,0)+A[b]-A[a-1]);
                }
                if(opr[0]=='H')
                {
                    inputt(a,b);input(c);
                    printf("%lld
    ",cT.querry(cT.root[c],a,b,1,n,0)+A[b]-A[a-1]);
                }
                if(opr[0]=='B')
                    input(cur);
            }
        }
        return 0;
    }
  • 相关阅读:
    Linux 安装中文man手册
    centos6.9使用NTFS-3G挂载ntfs文件系统
    Linux基础知识之挂载详解(mount,umount及开机自动挂载)
    技术点总结
    SQL 分组后获取其中一个字段最大值的整条记录 【转载】
    线程池之ThreadPool类与辅助线程
    Task.Run使用默认线程池
    VS生成事件
    线程池之ThreadPoolExecutor使用
    Sql笔记
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580581.html
Copyright © 2020-2023  润新知