主席树 hdu 4348

题意:有一个由n个数组成的序列,有4中操作:

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时间,且下一秒的时间从t开始

按时间建立主席树,主席树上的每一棵线段树维护[1,n]这段序列的信息,这里成段更新的时候要注意,以往写线段树的时候,都是把lazy标记向下传,但是写主席树的时候每一次下传,那么新的节点数就会非常多,会爆内存,所以我们不把lazy操作下传,只是在询问的时候,最后累加的答案加上每一个父亲节点上的lazy值。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #include<iostream>
  5 using namespace std;
  6 typedef long long ll;
  7 const int maxn=1e5+10;
  8 ll a[maxn];
  9 int root[maxn];
 10 struct node
 11 {
 12     int ln,rn;
 13     ll lazy,sum;
 14 }tree[maxn*30]; int cnt;
 15 void build(int &x,int l,int r)
 16 {
 17     ++cnt;x=cnt;
 18     tree[x].lazy=0;
 19     if(l==r){
 20         tree[x].sum=a[l];
 21         return;
 22     }
 23     int mid=l+r>>1;
 24     build(tree[x].ln,l,mid);
 25     build(tree[x].rn,mid+1,r);
 26     tree[x].sum=tree[tree[x].ln].sum+tree[tree[x].rn].sum;
 27 }
 28 void update(int &x,int y,int L,int R,int l,int r,int val)
 29 {
 30     tree[++cnt]=tree[y];
 31     x=cnt;
 32     if(L==l&&R==r){
 33         tree[cnt].lazy+=val;
 34         tree[cnt].sum+=(R-L+1)*val;
 35         return;
 36     }
 37     tree[x].sum+=(R-L+1)*val;
 38     int mid=l+r>>1;
 39     if(R<=mid) update(tree[x].ln,tree[y].ln,L,R,l,mid,val);
 40     else if(L>mid) update(tree[x].rn,tree[y].rn,L,R,mid+1,r,val);
 41     else{
 42         update(tree[x].ln,tree[y].ln,L,mid,l,mid,val);
 43         update(tree[x].rn,tree[y].rn,mid+1,R,mid+1,r,val);
 44     }
 45 }
 46 ll query(int root,int L,int R,int l,int r)
 47 {
 48     ll ans=0;
 49     if(l==L&&r==R) return tree[root].sum;
 50     ans+=(ll)tree[root].lazy*(ll)(R-L+1);
 51     int mid=l+r>>1;
 52     if(R<=mid) ans+=query(tree[root].ln,L,R,l,mid);
 53     else if(L>mid) ans+=query(tree[root].rn,L,R,mid+1,r);
 54     else{
 55         ans+=query(tree[root].ln,L,mid,l,mid);
 56         ans+=query(tree[root].rn,mid+1,R,mid+1,r);
 57     }
 58     return ans;
 59 }
 60 void init()
 61 {
 62     cnt=0;
 63 }
 64 int main()
 65 {
 66     int n,m;
 67     while(scanf("%d%d",&n,&m)!=EOF){
 68         init();
 69         for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
 70         int now=0;
 71         build(root[0],1,n);
 72         char t1[3];int t2,t3,t4;
 73         while(m--){
 74             scanf("%s",t1);
 75             if(t1[0]==‘Q‘){
 76                 //当前时间线;
 77                 scanf("%d%d",&t2,&t3);
 78                 ll ans=query(root[now],t2,t3,1,n);
 79                 printf("%lld\n",ans);
 80             }
 81             else if(t1[0]==‘C‘){
 82                 now++;
 83                 scanf("%d%d%d",&t2,&t3,&t4);
 84                 update(root[now],root[now-1],t2,t3,1,n,t4);
 85             }
 86             else if(t1[0]==‘H‘){
 87                 //某个时间线;
 88                 scanf("%d%d%d",&t2,&t3,&t4);
 89                 ll ans=query(root[t4],t2,t3,1,n);
 90                 printf("%lld\n",ans);
 91             }
 92             else{
 93                 //返回某个时间线;
 94                 scanf("%d",&t2);
 95                 now=t2;
 96             }
 97         }
 98     }
 99     return 0;
100 }

原文地址:https://www.cnblogs.com/pangbi/p/11667420.html

时间: 2024-10-18 04:57:45

主席树 hdu 4348的相关文章

hdu 4348 To the moon(主席树区间操作)

题目链接:hdu 4348 To the moon 题意: 给你n个数,有m个操作. 1.给区间[l,r]的所有数+d,并且时间戳+1 2.询问当前时间戳的区间和. 3.询问过去时间戳t的区间和. 4.退回到时间戳t. 题解: 直接上主席树. 不过区间操作的时候push_down空间似乎不是那么够用. 所有把push_down这个操作去掉. 用一个标记记录当前这个区间的累加. 询问的时候就将这个累加传下去.(具体看代码) 最后还有退回状态t的时候可以把cnt=root[t+1], 因为后面的内存

hdu 4348 To the moon (主席树)

hdu 4348 题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q l r:查询当前时间戳区间[l,r]中所有数的和 . (3)H l r t:查询时间戳t区间[l,r]的和 . (4)B t:将当前时间戳置为t . 所有操作均合法 . 解法: 很明显是一道主席树的题 . 对于每一次区间加法都新建节点建一棵线段树,加个懒惰标记就行了,查询的话直接线段树区间求和 . 不过感觉这一题就是为可持续化数据结构写的,特别是时间戳

HDU - 4348 To the moon(主席树区间更新)

题目链接:To the moon 题意:给个数组,三种操作,第一种询问当前区间[l,r]的和,第二种给区间[l,r]的每一个数加上d,第三种询问在第几次修改后[l,r]的权值 题解:如果这题只询问区间和更新,简单建棵线段树维护区间和用延时标记就可以了,但是它询问第几次修改之后一段区间的值,这样的话刚才的方法就不好用,那我们可不可以,在每次修改之后的重新建一棵线段树呢?直接重新建的话空间会爆,这个时候就可以用??币的主席树(没学过主席树可以先做一下这个),每次的修改只会再新增logN个节点,先把给

HDU 4348 To the moon(主席树 区间更新)题解

题意: 给一个数组A[1] ~ A[n],有4种操作: Q l r询问l r区间和 C l r v给l r区间每个数加v H l r t询问第t步操作的时候l r区间和 B t返回到第t步操作 思路: 用主席树维护常规的线段树.我们之前已经知道了主席树单点更新,只要新增一条链就ok了,区间更新也有点差不多.我们每次要更新都用一个lazy标记,但是显然我们不能去更新那些已经存在的区间,那么我们就新建出所有要更新的区间.因为可持久化线段树有些结点不是自己的,所以我们不能直接简单的push up和pu

hdu 4605 Magic Ball Game (在线主席树/离线树状数组)

hdu 4605 题意: 有一颗树,根节点为1,每一个节点要么有两个子节点,要么没有,每个节点都有一个权值wi .然后,有一个球,附带值x . 球到达某个节点上,如果x==wi,那么球停在这个节点上 .当然,这个点是叶子节点也会停止 . 如果x<wi,那么有1/2的概率走向左子树,有1/2的概率走向右子树 . 如果x>wi,那么有1/8的概率走向左子树,有7/8的概率走向右子树 . 问球经过v节点的概率 .(停在v节点也算) 解法: 在线的话每一个节点建一棵根节点到该节点的线段树,离线的话就先

HDU 2665(主席树,无修改第k小)

Kth number                                                 Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                                                        Total Submission(s): 10682    Accep

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

HDU 4417:Super Mario(主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=4417 题意是:给出n个数和q个询问,每个询问有一个l,r,h,问在[l,r]这个区间里面有多少个数是小于等于h的. 思路:比较裸的主席树,注意题意给的区间是从[0,n-1],一开始看错导致想错了很多东西.询问的时候如果m < h,那么左子树全部都是小于 h 的,就加上左子树的 sum,继续查右子树,否则就查左子树.最后 l == r 的时候要判下 h >= l,因为这个也错了几次.从师兄那里学习到了如果找一

HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5101    Accepted Submission(s): 2339 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping abilit