hdu 6315 Naive Operations(线段树)

题目链接

题意:n个数,先给你一个集合b的值,集合a里的元素初始都为0。给你m个操作,add x y:表示a集合里x~y的值都加上1,query x y:表示计算ai/bi(i = x,x+1...y)的和,并输出。

这题多校赛的时候有一点想法,但是感觉很难实现,本来想的是能不能判断这段区间的最小值b是多少,如果总和的值大于最小值b则向下更新,但是感觉不好实现,看了大佬的题解,才知道他们是反过来做的。有时候思路不能太正着想,还是得反过来,有时候会发现很神奇的事情(说到底还是我菜啊)

思路:用线段树来做,设一个变量Min,初始Min为这个区间的最小的b,然后每一次更新区间都把最小值--,如果最小值等于0的时候则向下更新子节点,如果l == r的时候则num++,并且把Min重新设为b[l]。好多地方都有pushdown()和updown(),千万别漏了,漏了就凉凉了。

AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn = 1e5+10;
struct Node{
    int Min, num;
}node[maxn<<2];
int add[maxn<<2],b[maxn];

int min(int a,int b){
    return a<b?a:b;
}

void updown(int rt){
    node[rt].num = node[rt<<1].num+node[rt<<1|1].num;
    node[rt].Min = min(node[rt<<1].Min,node[rt<<1|1].Min);
}

void build(int l,int r,int rt){
    add[rt] = 0;
    if(l == r){
        node[rt].Min = b[l];
        node[rt].num = 0;
        return;
    }
    int m = l+r>>1;
    build(l, m, rt<<1);
    build(m+1, r, rt<<1|1);
    updown(rt);
}

void pushdown(int rt,int l,int r){
    if(add[rt]){
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        node[rt<<1].Min -= add[rt];
        node[rt<<1|1].Min -= add[rt];
        add[rt] = 0;
    }
}

void change(int rt,int l,int r){    //如果存在Min等于0,则更新其子节点
    if(l == r){                    //当达到叶子节点的时候,就可以更新num值
        node[rt].num++;
        node[rt].Min = b[l];
        return;
    }
    pushdown(rt, l, r);           
    int m = l+r>>1;
    if(node[rt<<1].Min == 0)
        change(rt<<1, l, m);
    if(node[rt<<1|1].Min == 0)
        change(rt<<1|1, m+1, r);
    updown(rt);

}


void update(int L,int R,int l,int r,int rt){
    if(node[rt].Min == 0){
        change(rt, l, r);
    }
    if(L <= l && r <= R){
        node[rt].Min--;
        add[rt]++;
        if(node[rt].Min == 0){
            change(rt, l, r);
        }
        return;
    }
    pushdown(rt, l, r);
    int m = l+r>>1;
    if(L <= m)
        update(L, R, l, m, rt<<1);
    if(R > m)
        update(L, R, m+1, r, rt<<1|1);
    updown(rt);
}

int query(int L,int R,int l,int r,int rt){
    if(node[rt].Min == 0){   
        change(rt,l,r);
    }
    if(L <= l&& r <= R){
        return node[rt].num;
    }
    pushdown(rt,l,r);
    int m = l+r>>1, ans = 0;
    if(L <= m)
        ans += query(L, R, l, m, rt<<1);
    if(R > m)
        ans += query(L, R, m+1, r, rt<<1|1);
    updown(rt);
    return ans;
}

int main(){
    int n, m, x, y, i;
    char ch[10];
    while(scanf("%d%d",&n,&m)!=EOF){
        for(i = 1; i <= n; i++){
            scanf("%d",&b[i]);
        }
        build(1, n, 1);
        while(m--){
            scanf("%s%d%d",ch,&x,&y);
            if(ch[0] == 'a')
                update(x, y, 1, n, 1);
            else
                printf("%d\n",query(x, y, 1, n, 1));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhuyou_/article/details/81217184
今日推荐