zoukankan      html  css  js  c++  java
  • HDU 4348 To the moon (主席树区间更新)

    题意:首先给你n个数,开始时间为0,最后按照操作输出

    给你四种操作:

    1. C l r d :  在(l,r)区间都加上d,时间加一
    2. Q l r :  询问现在(l,r)的区间和
    3. H l r t :  询问在t的时间(l,r)的区间和
    4. B t : 直接回到t的时间

    题解:首先是区间修改区间查询,可以想到线段树,接着就是询问历史版本与回到历史版本,这样就是主席树了

    首先我们知道普通主席树是单点修改,并支持历史版本的区间求和与回到历史版本(就是这删除之后的树),仅仅只是因为它存了多棵线段树

    而我们这儿是要进行区间修改,所以第一反应就是模拟线段树的lazy标记,并在查询时再更新再建树,但是这样会卡空间

    因此我们需要这样想,模拟lazy标记进行重建树(最多建立2*log2(n)个节点)是必须的,但是查询时就不需要重建树了

    这样我们就需要记录两个值:sum代表这一段中被增加区间的与此这一段的区间相交的总和,com代表这一段都需要增加这么多

    这时我们查询时就需要每次加上com与待查询的区间相交的值(加上之前更新的),最后再包含的区间里加上sum再减去这儿com与待查询的区间相交的值(重复了)

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<iomanip>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    typedef unsigned long long ull;
    const int Inf=1<<28;
    const ll INF=1ll<<60;
    const double Pi=acos(-1.0);
    const int Mod=1e9+7;
    const int Max=1e5+7;
    int root[Max],tot;
    struct node
    {
        int lef,rig;
        ll sum,com;//相交总共的和 这一段每个点都加上这个
    }msegtr[Max*40];
    ll pre[Max];//把原来的数放入前缀和里,主席树里仅仅更新修改的值
    void Init(int &cnt)
    {
        cnt=0;
        msegtr[0].lef=msegtr[0].rig=0;
        msegtr[0].sum=msegtr[0].com=0ll;
        root[0]=0,tot=0;
        pre[0]=0ll;
        return;
    }
    int Jud(int sta,int enn,int lef,int rig)//关键的区间交
    {
        return max(min(rig,enn)-max(lef,sta)+1,0);
    }
    void Create(int sta,int enn,int &x,int y,int lef,int rig,int com)
    {
        msegtr[++tot]=msegtr[y];
        msegtr[tot].sum+=(ll)com*Jud(sta,enn,lef,rig);
        x=tot;
        if(sta>=lef&&enn<=rig)//模拟线段树区间更新
        {
            msegtr[tot].com+=com;//这一段每个点都加上这个
            return;
        }
        int mid=dir(sta+enn,1);
        if(mid>=lef)
            Create(sta,mid,msegtr[x].lef,msegtr[y].lef,lef,rig,com);
        if(mid<rig)
            Create(mid+1,enn,msegtr[x].rig,msegtr[y].rig,lef,rig,com);
        return;
    }
    ll Query(int sta,int enn,int x,int lef,int rig)
    {
        if(sta>=lef&&enn<=rig)
        {
            return msegtr[x].sum-msegtr[x].com*Jud(sta,enn,lef,rig);//多加了,要减去
        }
        int mid=dir(sta+enn,1);
        ll ans=0ll;
        if(mid>=lef)
        {
            ans+=Query(sta,mid,msegtr[x].lef,lef,rig)+msegtr[msegtr[x].lef].com*Jud(sta,mid,lef,rig);//加上区间交的值
        }
        if(mid<rig)
        {
            ans+=Query(mid+1,enn,msegtr[x].rig,lef,rig)+msegtr[msegtr[x].rig].com*Jud(mid+1,enn,lef,rig);
        }
       return ans;
    }
    int main()
    {
        int n,m,temp,cnt;
        int lef,rig,sum;
        char str[10];
        while(~scanf("%d %d",&n,&m))
        {
            Init(cnt);
            for(int i=1;i<=n;++i)
            {
                scanf("%d",&temp);
                pre[i]=pre[i-1]+temp;
            }
            for(int i=0;i<m;++i)
            {
                scanf("%s",str);
                if(str[0]=='C')
                {
                    scanf("%d %d %d",&lef,&rig,&sum);
                    Create(1,n,root[cnt+1],root[cnt],lef,rig,sum);
                    cnt++;
                }
                else if(str[0]=='Q')
                {
                    scanf("%d %d",&lef,&rig);
                    printf("%I64d
    ",Query(1,n,root[cnt],lef,rig)+pre[rig]-pre[lef-1]);
                }
                else if(str[0]=='H')
                {
                    scanf("%d %d %d",&lef,&rig,&sum);
                    printf("%I64d
    ",Query(1,n,root[sum],lef,rig)+pre[rig]-pre[lef-1]);
                }
                else
                {
                    scanf("%d",&sum);
                    if(sum<cnt)
                    {
                        tot=root[sum+1];
                        cnt=sum;//存储线段树,这样就代表摧毁了后面更新的树
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    Go基础系列:流程控制结构
    Go基础系列:数据类型转换(strconv包)
    Go基础系列:简单数据类型
    Go基础系列:常量和变量
    Go基础系列:map类型
    Go基础系列:Go slice详解
    go基础系列:数组
    Go基础系列:import导包和初始化阶段
    Go基础系列:构建go程序
    go基础系列:结构struct
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5933760.html
Copyright © 2011-2022 走看看