1. 程式人生 > >hdu 6315 Naive Operations(線段樹 加ok標記)

hdu 6315 Naive Operations(線段樹 加ok標記)

題目連結

看大佬部落格:https://www.cnblogs.com/chenquanwei/p/9374234.html

題意:有兩個操作:

1:a陣列l到r的區間都加1;

2:計算l到r內a[i]/b[i]的值的和;

可以只用一個b陣列,每次進行1操作的時候就給相應位置減一,減到零以後就給相應的答案加一(答案就是記錄a[i]/b[i]的值,只有b[i]減到一次零,答案才加一),同時把b陣列的值在置為初始值;

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn = 1e5+10;
int n,m,x,y;
char q[10];
int a[maxn];//記錄初始的b陣列的值

struct node{
    int mi,add,sum;
} t[maxn<<2];
/*
mi是記錄當前的值,也是區間的最小值,當區間的最小值減到0,
就查詢是哪個子節點減到了0,將其答案加一後,mi賦回初始值;
add是記錄訪問次數,記錄的是負值,每次更新的時候,
只要add不為0,就把add標記往下推,然後把add置為0;
sum記錄答案;
*/

void build(int l,int r,int rt){
    if(l==r){
        t[rt].mi = a[l];
        t[rt].add=t[rt].sum=0;
        return;
    }

    int mid = (l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);

    t[rt].mi = min(t[rt<<1].mi,t[rt<<1|1].mi);
    t[rt].sum =t[rt].add = 0;
}

void pushdown(int l,int r,int rt){//標記往下推
    if(!t[rt].add) return;//已經更新過了或者不需要更新,直接返回;

    t[rt<<1].mi += t[rt].add;
    t[rt<<1|1].mi += t[rt].add;
    t[rt<<1].add += t[rt].add;
    t[rt<<1|1].add += t[rt].add;
    t[rt].add=0;
}

//ok表示區間內是否存在答案,即mi等於0;ok為1表示不存在,存在就立即更新節點
void update(int L,int R,int l,int r,int rt,bool ok){//更新
    if(L<=l&&r<=R){
        if(ok){
            t[rt].add--;
            t[rt].mi--;
        }
        if(t[rt].mi) return;//不存在值直接返回
        if(l==r){
            if(!t[rt].mi) t[rt].sum++,t[rt].mi=a[l];
//有答案,更新mi和sum,add已經在它的標記往下推的時候被置為0了;
            return;//子節點,不往下推了,返回;
        }
        ok = 0;
    }
    pushdown(l,r,rt);//標記往下推

    int mid = (l+r)>>1;
    if(L<=mid) update(L,R,l,mid,rt<<1,ok);
    if(R>mid) update(L,R,mid+1,r,rt<<1|1,ok);

    t[rt].mi = min(t[rt<<1].mi,t[rt<<1|1].mi);
    t[rt].sum = t[rt<<1].sum + t[rt<<1|1].sum;
}

int query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R) return t[rt].sum;

    int ans = 0,mid = (l+r)>>1;
    if(L<=mid) ans += query(L,R,l,mid,rt<<1);
    if(R>mid) ans+=query(L,R,mid+1,r,rt<<1|1);
    return ans;
}

int main()
{
    while(~scanf("%d%d",&n,&m)){
        for(int i = 1;i <= n;i++) scanf("%d",&a[i]);

        build(1,n,1);

        while(m--){
            scanf("%s%d%d",q,&x,&y);
            if(q[0]=='a') update(x,y,1,n,1,1);
            else printf("%d\n",query(x,y,1,n,1));
        }
    }
    return 0;
}