【题解】[HDU6315] Naive Operations【线段树 树状数组 调和级数】

题目链接Vjudge

题意

给定排列 \(b\),维护序列 \(a\)

  • 区间 \(+1\)
  • \(\lfloor \dfrac{b_i}{a_i}\rfloor\) 的区间和。

\(n,m\leq 10^5\)

题解

用一棵线段树维护 \(b_i-(a_i\bmod b_i)\) 的区间最小值,每次修改会导致一些 \(\lfloor \dfrac{a_i}{b_i}\rfloor\ +1\),对于这些点,在树状数组上依次修改。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int b[N],n;
int t[N<<2],tag[N<<2],r[N];
int qry(int p){ int ans=0;for(;p;p-=(p&-p))ans+=r[p];return ans; }
void mdf(int p){ for(;p<=n;p+=(p&-p))r[p]++; }
void pushup(int x){ t[x]=max(t[x<<1],t[x<<1|1]); }
void pushdown(int x){
    tag[x<<1]+=tag[x];
    tag[x<<1|1]+=tag[x];
    t[x<<1]+=tag[x];
    t[x<<1|1]+=tag[x];
    tag[x]=0;
}
void upd(int x,int nl,int nr){
    if(nl==nr){
        if(t[x]==0)t[x]=-b[nl],mdf(nl);
        return;
    }
    pushdown(x);
    int mid=nl+nr>>1;
    while(t[x<<1]==0)upd(x<<1,nl,mid);
    while(t[x<<1|1]==0)upd(x<<1|1,mid+1,nr);
    pushup(x);
}
void modify(int l,int r,int x,int nl,int nr){
    if(nr<l||nl>r)return;
    if(l<=nl&&nr<=r){
        tag[x]++;
        t[x]++;
        return;
    }
    pushdown(x);
    int mid=nl+nr>>1;
    modify(l,r,x<<1,nl,mid);
    modify(l,r,x<<1|1,mid+1,nr);
    pushup(x);
}
void build(int x,int l,int r){
    if(l==r){
        t[x]=-b[l];
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}

char s[7];
int main(){
    int q;
    while(scanf("%d%d",&n,&q)!=EOF){
        for(int i=1;i<=n;i++)scanf("%d",b+i);
        memset(r,0,sizeof(r));
        memset(t,0,sizeof(t));
        memset(tag,0,sizeof(tag));
        build(1,1,n);
        while(q--){
            int l,r;
            scanf("%s%d%d",s,&l,&r);
            if(s[0]=='a')
                modify(l,r,1,1,n),upd(1,1,n);
            else
                printf("%d\n",qry(r)-qry(l-1));
        }
    }
    return 0;
}

posted @ 2021-01-08 15:24  破壁人五号  阅读(93)  评论(0编辑  收藏  举报