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

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=4348

    题意:

    4种操作:

    C l r c   区间[l,r]加c,时间+1

    Q l r    询问当前时间区间[l,r]的和

    H l  r c  询问在时间t时,区间[l,r]的和

    B x  回到时间x

    思路:

    涉及历史版本的询问,很容易想到主席树,然后尝试用线段树的思路用主席树写了下,疯狂WA,TLE,后面看了下其他人的博客。。。。发现不能加pushdown操作,因为一般来说pushdown更新完当前点后会向下更新子树,这样会新增很多点,其实我们可以将向下更新子树的操作省略,每次从根节点向下到需要的区间的过程中加上经过的点的lazy值就好了这样就实现了向下更新,且不会建过多的点。

    还有因为计算从根到所求区间过程经过的标记数组对所求区间值的影响我们写法是:lazy*(R-L+1)所以查询操作没有用完全版线段树那种写法,换了一种,之前的写法,L,R,是不变的,但是我们是需要通过改变L,R,来表示当前标记数组作用的区间,需要改变L,R。

    表达能力好弱啊。。。感觉讲不清楚想表达的思路。。。。难受

    实现代码:、

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int M = 1e5+10;
    ll a[M],sum[M*40],lazy[M*40];
    int ls[M*40],rs[M*40],root[M],idx;
    void pushup(int l,int r,int rt){
        sum[rt] = sum[ls[rt]] + sum[rs[rt]] + 1LL*(r-l+1)*lazy[rt];
    }
    
    void build(int l,int r,int &rt){
        rt = ++idx;lazy[rt]  = 0; sum[rt] = 0;
        if(l == r){
            sum[rt] = a[l];
            return ;
        }
        int m = (l + r) >> 1;
        build(l,m,ls[rt]);
        build(m+1,r,rs[rt]);
        pushup(l,r,rt);
    }
    
    void update(int old,int &rt,int L,int R,ll c,int l,int r){
        rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old];
        sum[rt] = sum[old]; lazy[rt] = lazy[old];
        if(L <= l&&R >= r){
            sum[rt] += 1LL*(r-l+1)*c;
            lazy[rt] += c;
            return ;
        }
        int m = (l + r) >> 1;
        if(L <= m) update(ls[old],ls[rt],L,R,c,l,m);
        if(R > m) update(rs[old],rs[rt],L,R,c,m+1,r);
        pushup(l,r,rt);
    }
    
    ll query(int L,int R,int l,int r,int rt){
        if(L <= l&&R >= r)  return sum[rt];
        int m = (l + r) >> 1;
        ll ans = 1LL*(R-L+1)*lazy[rt];
        /* 这种写法是不对的
        if(L <= m) ans += query(L,R,l,m,ls[rt]);
        if(R > m) ans += query(L,R,m+1,r,rs[rt]);
        */
        //正确写法
        if(R <= m) ans += query(L,R,l,m,ls[rt]);
        else if(L > m) ans += query(L,R,m+1,r,rs[rt]);
        else{  
            ans += query(L,m,l,m,ls[rt]);   
            ans += query(m+1,R,m+1,r,rs[rt]);
        }
        return ans;
    }
    
    char op[3];
    int main()
    {
        int n,q,x,y;
        ll z;
        while(scanf("%d%d",&n,&q)!=EOF){
        idx = 0;memset(root,0,sizeof(root));
        for(int i = 1;i <= n;i ++)
            scanf("%lld",&a[i]);
        build(1,n,root[0]);
        int tim = 0;
        for(int i = 1;i <= q;i ++){
            scanf("%s",op);
            if(op[0] == 'C'){
                scanf("%d%d%lld",&x,&y,&z);
                update(root[tim],root[tim+1],x,y,z,1,n);
                tim++;
            }
            else if(op[0] == 'Q'){
                scanf("%d%d",&x,&y);
                printf("%lld
    ",query(x,y,1,n,root[tim]));
            }
            else if(op[0] == 'H'){
                int t;
                scanf("%d%d%d",&x,&y,&t);
                printf("%lld
    ",query(x,y,1,n,root[t]));
            }
            else if(op[0] == 'B'){
                scanf("%d",&x);
                tim = x;
            }
        }
        }
        return 0;
    }
  • 相关阅读:
    sqlserver表结构导出excel格式
    c#对象深复制demo
    aspose.cells导出Demo
    复制表结构数据至另一数据库
    C#安全类型转换基于convert
    c# winform devexpress TreeList过滤和绑定
    万能分页存储过程
    WebSocket简单使用
    本地搭建持续集成(AzureDevops)
    centos 7 安装nginx并启动(笔记)
  • 原文地址:https://www.cnblogs.com/kls123/p/9595418.html
Copyright © 2011-2022 走看看