• 【HDU4348】To The Moon-主席树(可持久化线段树)区间修改+区间询问


    测试地址:To The Moon

    题目大意:维护一个长度为N的数列,支持以下操作:将其中的某个区间内元素加上一个值然后将时间戳+1,询问当前时间戳内某一个区间内元素的和,询问某个时间戳内某一个区间内元素的和,将时间戳重置回某一个前面的时间。

    做法:这道题一看就是主席树了,按照主席树区间修改和区间询问的方法去做就行了。但是这道题有点卡空间,如果空间爆了可以用以下方式减少空间的用量:不用下放标记,只需要在询问时实时记录从根到某个节点路径上所有标记的和,就相当于覆盖在这个节点上的标记了,但是要特别注意这种情况下的pushup,在pushup时不要忘了加上该区间原来的标记即可。最后就是注意数据可能爆int,要用long long来存储区间和。

    题外话:To The Moon这个游戏我当初玩过,在做题时又看到这个还是挺兴奋的^_^,据说还是国人作品,很厉害啊~

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,a[100010],rt[100010],tot,now;
    struct segnode
    {
      int lc,rc;
      long long sum,p;
    }seg[4000010];
    
    void buildtree(int &no,int l,int r)
    {
      no=++tot;
      seg[no].lc=seg[no].rc=seg[no].p=0;
      if (l==r)
      {
        seg[no].sum=a[l];
        return;
      }
      int mid=(l+r)>>1;
      buildtree(seg[no].lc,l,mid);
      buildtree(seg[no].rc,mid+1,r);
      seg[no].sum=seg[seg[no].lc].sum+seg[seg[no].rc].sum;
    }
    
    void modify(int &no,int last,int l,int r,int s,int t,long long c)
    {
      no=++tot;
      seg[no]=seg[last];
      if (l>=s&&r<=t)
      {
        seg[no].p+=c;
    	seg[no].sum+=c*(r-l+1);
    	return;
      }
      int mid=(l+r)>>1;
      if (s<=mid) modify(seg[no].lc,seg[last].lc,l,mid,s,t,c);
      if (t>mid) modify(seg[no].rc,seg[last].rc,mid+1,r,s,t,c);
      seg[no].sum=seg[seg[no].lc].sum+seg[seg[no].rc].sum+(r-l+1)*seg[no].p;
    }
    
    long long query(int no,int l,int r,int s,int t,long long presum)
    {
      if (l>=s&&r<=t) return seg[no].sum+presum*(r-l+1);
      int mid=(l+r)>>1;
      long long sums=0;
      if (s<=mid) sums+=query(seg[no].lc,l,mid,s,t,presum+seg[no].p);
      if (t>mid) sums+=query(seg[no].rc,mid+1,r,s,t,presum+seg[no].p);
      return sums;
    }
    
    int main()
    {
      int t=0;
      while(scanf("%d%d",&n,&m)!=EOF)
      {
        t++;
    	if (t>1) printf("
    ");
        tot=now=0;
        for(int i=1;i<=n;i++)
          scanf("%d",&a[i]);
        buildtree(rt[0],1,n);
        
        for(int i=1;i<=m;i++)
        {
          char op[10];
    	  int a,b,c;
    	  scanf("%s",op);
    	  if (op[0]=='C')
    	  {
    	    scanf("%d%d%d",&a,&b,&c);
    		modify(rt[now+1],rt[now],1,n,a,b,c);
    		now++;
    	  }
    	  if (op[0]=='Q')
    	  {
    	    scanf("%d%d",&a,&b);
    		printf("%lld
    ",query(rt[now],1,n,a,b,0));
    	  }
    	  if (op[0]=='H')
    	  {
    	    scanf("%d%d%d",&a,&b,&c);
    		printf("%lld
    ",query(rt[c],1,n,a,b,0));
    	  }
    	  if (op[0]=='B')
    	  {
    	    scanf("%d",&a);
    		now=a;
    	  }
        }
      }
      
      return 0;
    }
    


  • 相关阅读:
    元祖操作
    列表操作
    字符串操作
    zabbix监控脚本
    nginx 使用php-fpm的配置php环境参数
    网卡切换脚本
    mysql数据备份脚本
    docker概念
    网络链路质量监控smokeping
    搭建speedtest
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793807.html
Copyright © 2020-2023  润新知