zoukankan      html  css  js  c++  java
  • HDU 6315 Naive Operations 【势能线段树】

    <题目链接>

    题目大意:

    给出两个序列,a序列全部初始化为0,b序列为输入值。然后有两种操作,add x y就是把a数组[x,y]区间内全部+1,query x y是查询[x,y]区间内∑[ai/bi]。([ai/bi]代表ai/bi后向下取整)

    解题分析:

    首先,如果每次+1都暴力更新到每个叶子节点肯定会超时,但是如果不更新到叶子节点又不好维护每个节点对应区间 ∑[ai/bi] 的值,所以我们可以每个节点都维护四个值。sum值代表这个区间每个节点整数部分的所有数之和,lazy进行懒惰标记,避免每次更新到叶子节点,mxa记录该区间内分子的最大值,mnb记录该区间内分母的最小值。之所以要维护这两个最大最小值是因为,当进行区间整体+1操作的时候,如果该区间内最大的分子都小于分母时,说明这个区间在进行+1操作后,并没有对该区间的sum值做出贡献,所以此时就可以将这个+1操作lazy到这个节点;但是如果对区间整体+1后,最大分子大于等于最小分母,此时,就需要继续向下更新,直到找到那个(或者几个)分子大于等于分母的根节点,然后将该节点的sum+1,同时将b值加上原始的brr[l]值(其实我不太明白这一步为什么要这么做,我觉的这步等效于该点的mxa值-该点的mnb值啊,然而这样改了以后超时  T_T)。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define Lson rt<<1,l,mid
     7 #define Rson rt<<1|1,mid+1,r
     8 const int M =1e5+10;
     9 
    10 int n,m;
    11 struct Tree{
    12     int lazy,sum;
    13     int mxa,mnb;
    14 }tr[M<<2];
    15 int brr[M];
    16 
    17 void Pushdown(int rt){
    18     if(tr[rt].lazy){
    19         int tmp=tr[rt].lazy;
    20         tr[rt<<1].lazy+=tmp,tr[rt<<1|1].lazy+=tmp;
    21         tr[rt<<1].mxa+=tmp,tr[rt<<1|1].mxa+=tmp;
    22         tr[rt].lazy=0;
    23     }
    24 }
    25 void Pushup(int rt){
    26     tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
    27     tr[rt].mxa=max(tr[rt<<1].mxa,tr[rt<<1|1].mxa);       //维护该区间内分子的最大值和分母的最小值
    28     tr[rt].mnb=min(tr[rt<<1].mnb,tr[rt<<1|1].mnb);
    29 }
    30 void build(int rt,int l,int r){    //初始化
    31     tr[rt].lazy=0;
    32     if(l==r){
    33         tr[rt].mxa=tr[rt].sum=0;     
    34         tr[rt].mnb=brr[l];
    35         return;
    36     }
    37     int mid=(l+r)>>1;
    38     build(Lson);
    39     build(Rson);
    40     Pushup(rt);
    41 }
    42 void update(int rt,int l,int r,int L,int R){      //这个函数是本题的关键
    43     if(L<=l&&r<=R){
    44         tr[rt].mxa++;
    45         if(tr[rt].mxa<tr[rt].mnb){   //如果最大的分子小于最大的分母,说明这个区间内的所有叶子在分子+1之后,没有对sum值多做出贡献,所以我们先将这个操作lazy在这个节点
    46             tr[rt].lazy++;
    47             return;
    48         }
    49         if(l==r&&tr[rt].mxa>=tr[rt].mnb){    //如果向下找到了那个分子大于等于分母的叶子节点,那么该节点贡献+1,且将分母加上最初始的防御值,相当于将该真分数的整数部分提出后,再将其变成假分数,方便以后继续统计贡献
    50             tr[rt].sum++;
    51             tr[rt].mnb+=brr[l];      //我觉的这一步应该等效于tr[rt].mxa-=tr[rt].mnb啊,然而这样改了以后超时
    52             return;                   
    53         }
    54     }
    55     Pushdown(rt);
    56     int mid=(l+r)>>1;
    57     if(L<=mid)update(Lson,L,R);
    58     if(R>mid)update(Rson,L,R);
    59     Pushup(rt);
    60 }
    61 int query(int rt,int l,int r,int L,int R){       //查询该区间内所有数的整数部分之和
    62     if(L<=l&&r<=R)return tr[rt].sum;      
    63     Pushdown(rt);
    64     int ans=0;
    65     int mid=(l+r)>>1;
    66     if(L<=mid)ans+=query(Lson,L,R);
    67     if(R>mid)ans+=query(Rson,L,R);
    68     return ans;
    69 }
    70 int main(){
    71     while(~scanf("%d%d",&n,&m)){
    72         for(int i=1;i<=n;i++)
    73             scanf("%d",&brr[i]);
    74         build(1,1,n);
    75         char op[15];
    76         while(m--){
    77             int x,y;
    78             scanf("%s%d%d",&op,&x,&y);
    79             if(op[0]=='a')update(1,1,n,x,y);
    80             else printf("%d
    ",query(1,1,n,x,y));
    81         }
    82     }
    83     return 0;
    84 }

    2018-10-15

  • 相关阅读:
    JAVA学习日报 11/26
    JAVA学习日报 11/25
    大二寒假作业之JavaWeb
    大二寒假作业之JavaWeb
    大二寒假作业之JavaWeb
    大二寒假作业之《构建之法》读后感2
    大二寒假作业之Android
    大二寒假作业之《构建之法》读后感1
    大二寒假作业之android
    大二寒假作之Android
  • 原文地址:https://www.cnblogs.com/00isok/p/9791604.html
Copyright © 2011-2022 走看看