HDU-4348 To the moon(主席树区间修改 永久化标记)

简介: HDU-4348 To the moon(主席树区间修改 永久化标记)

link

题意:

给定一个长度为1 e 5的数组,有1 e 5次操作,操作有下面四种:

Clrd: 将[ l , r ]的值都加d,时间增加1

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

Hlrt: 询问t时间[ l , r ]的区间和

Bt :回到t时刻,并且t时刻之后的操作都不计

思路:

由于有不同时刻的数组,即对应不同个历史版本,考虑用主席树

但是这样,主席树进行p u s h d o w n操作的时候,公用节点都被修改,还是要新建树,空间不够

在结构体里记录一下l a z表示所有子区间的懒惰标记

修改的时候只在上层区间更新l a z,不下传

查询的时候,维护一个a d d,表示自顶向下的l a z的和,每次用a d d ∗ l e n 为区间长度)就是懒惰标记要增加的和;

这是因为对于不同时间公共的节点,不能改变l a z值,还会影响到之前的状态;

这样保证每次修改只会影响到l o g n个节点

空间复杂度:点击跳转

20200401134307494.png

代码:

const int maxn=1e5+7,mod=1e9+7,inf=0x3f3f3f3f;
int n,m,root[maxn],idx;
ll a[maxn];
struct node{
  int l,r;
  ll sum,laz;
}tr[maxn*32];
void pushup(int u,int l,int r){
  tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum+tr[u].laz*(r-l+1);
}
void build(int &now,int l,int r){
  now=++idx;//建立新线段树
  tr[now].sum=tr[now].laz=0;
  if(l==r){
    tr[now].sum=a[l];return ;///初始化
  }
  int mid=(l+r)/2;
  build(tr[now].l,l,mid);build(tr[now].r,mid+1,r);
  pushup(now,l,r);
}
void update(int &now,int las,int l,int r,int L,int R,int val){
  now=++idx;///对于修改的节点新建立一颗树
  tr[now]=tr[las];//先复制过来
  if(L<=l&&r<=R){//当前区间完全包含待修改区间的话
    tr[now].laz+=val;//永久化标记
    tr[now].sum+=val*(r-l+1);//求和
    return ;///及时返回 已经更新完了 不需要pushup操作
  }
  int mid=(l+r)/2;
  if(L<=mid) update(tr[now].l,tr[las].l,l,mid,L,R,val);
  if(R>mid) update(tr[now].r,tr[las].r,mid+1,r,L,R,val);
  pushup(now,l,r);
}
ll query(int now,int l,int r,int L,int R,ll add){
  //add为路径上的懒惰标记
  if(L<=l&&r<=R){
    return tr[now].sum+add*(r-l+1);///完全包含的话,值等于和加上标记的内容
  }
  ll ans=0;
  int mid=(l+r)/2;
  if(L<=mid) ans+=query(tr[now].l,l,mid,L,R,add+tr[now].laz);//注意沿途加标记
  if(R>mid) ans+=query(tr[now].r,mid+1,r,L,R,add+tr[now].laz);
  return ans;
}
int main(){
  while(~scanf("%d%d",&n,&m)){
    idx=0;
    int time=0;
    rep(i,1,n) a[i]=read;
    build(root[0],1,n);
    rep(i,1,m){
      char op[2];
      cin>>op;
      if(op[0]=='C'){
        int l=read,r=read,d=read;
        ++time;
        update(root[time],root[time-1],1,n,l,r,d);
      }
      else if(op[0]=='Q'){
        int l=read,r=read;
        printf("%lld\n",query(root[time],1,n,l,r,0));
      }
      else if(op[0]=='H'){
        int l=read,r=read,t=read;
        printf("%lld\n",query(root[t],1,n,l,r,0));
      }
      else time=read;
    }
  }
  return 0;
}
目录
相关文章
|
7月前
|
测试技术
最大连续子序列 (HDU - 1231)
最大连续子序列 (HDU - 1231)
|
7月前
|
算法 Java 编译器
☆打卡算法☆LeetCode 190. 颠倒二进制位 算法解析
☆打卡算法☆LeetCode 190. 颠倒二进制位 算法解析
|
7月前
【每日一题Day192】LC1033移动石子直到连续 | 分类讨论 贪心
【每日一题Day192】LC1033移动石子直到连续 | 分类讨论 贪心
38 0
|
算法 C++
剑指offer(C++)-JZ38:字符串的排列(算法-搜索算法)
剑指offer(C++)-JZ38:字符串的排列(算法-搜索算法)
|
机器学习/深度学习 Java
【每日一题Day64】LC1799N 次操作后的最大分数和 | 状态压缩dp 状态压缩+dfs+记忆化搜索
每个数字有两种状态,删除或者未删除,因此可以使用状态压缩记录未删除的数字情况state,便于使用位运算进行状态的遍历及转移;使用状态压缩dp找到将所以数字删除的最大分数
110 0
【每日一题Day64】LC1799N 次操作后的最大分数和 | 状态压缩dp 状态压缩+dfs+记忆化搜索
UPC-趾压板矩阵(强行找规律)
UPC-趾压板矩阵(强行找规律)
106 0
UPC-趾压板矩阵(强行找规律)
|
存储 机器学习/深度学习 人工智能
【Python 百练成钢】DNA、蛇形矩阵、Huffuman树、K-进制数、K倍区间、交换瓶子、第几个幸运数、四平方和、The 3n + 1 problem、大数乘法
【Python 百练成钢】DNA、蛇形矩阵、Huffuman树、K-进制数、K倍区间、交换瓶子、第几个幸运数、四平方和、The 3n + 1 problem、大数乘法
【Python 百练成钢】DNA、蛇形矩阵、Huffuman树、K-进制数、K倍区间、交换瓶子、第几个幸运数、四平方和、The 3n + 1 problem、大数乘法
|
Python
UPC组队赛第四场—— H: Boring Counting (主席树+二分)
UPC组队赛第四场—— H: Boring Counting (主席树+二分)
72 0
UPC-探险(线段树+二分)
UPC-探险(线段树+二分)
96 0
|
存储 机器学习/深度学习 安全
【刷穿 LeetCode】446. 等差数列划分 II - 子序列 :详解如何分析「序列 DP」问题
【刷穿 LeetCode】446. 等差数列划分 II - 子序列 :详解如何分析「序列 DP」问题