1. 程式人生 > >Naive Operations HDU - 6315

Naive Operations HDU - 6315

傳送門

  題意是給一個長度為n的a,b陣列,然後有2種操作,一種是a陣列l~r區間+1,第二種是查詢l~r區間ai/bi之和。維護區間內最大的a值和最小的b值,對一段區間進行成段更新後,如果maxa==minb說明往該節點的兒子節點更新可能會對該區間之和產生貢獻,那就更新下去,往下面更新時若找到了maxa==minb的葉子節點,則該葉子節點的minb加上其初始的值(b[l]),且區間和++,比如說2/2,將分母即該節點的minb+b[l],區間之和加1.若maxa<minb的話說明往該節點的兒子節點更新不可能會對該區間之和產生貢獻,因此不必更新下去了,在當前節點打個標記即可,查詢的話就和普通線段樹查詢一樣。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
#define ll long long
#define ls 2*rt
#define rs 2*rt+1
struct node
{
    ll sum;
    int l,r,lazy,maxa,minb;
    bool tag;
}tree[4*maxn];
int b[maxn+10];
inline void pushup(int rt)
{
    tree[rt].sum=tree[ls].sum+tree[rs].sum;
    tree[rt].maxa=max(tree[ls].maxa,tree[rs].maxa);
    tree[rt].minb=min(tree[ls].minb,tree[rs].minb);
}
inline void pushdown(int rt)
{
    if(tree[rt].tag)
    {
        tree[ls].maxa+=tree[rt].lazy;
        tree[rs].maxa+=tree[rt].lazy;
        tree[ls].tag=true;
        tree[ls].lazy+=tree[rt].lazy;
        tree[rs].tag=true;
        tree[rs].lazy+=tree[rt].lazy;
        tree[rt].tag=false;
        tree[rt].lazy=0;
    }
}
void build(int l,int r,int rt)
{
    tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].tag=false;
    tree[rt].lazy=0;
    if(l==r)
    {
        tree[rt].maxa=0;
        tree[rt].minb=b[l];
        tree[rt].sum=0;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
    pushup(rt);
}
void update(int l,int r,int rt)
{
    if(tree[rt].l>=l&&tree[rt].r<=r)
    {
        tree[rt].maxa++;
        if(tree[rt].maxa<tree[rt].minb)///滿足該條件則對rt節點對應區間更新不可能對區間和有貢獻,當然ls,rs也是一樣不會有貢獻的,因此不必更新到rt對應區間的每個葉子節點
        {
            tree[rt].tag=true;
            tree[rt].lazy++;
            return ;
        }
        else
            if(tree[rt].l==tree[rt].r)///滿足該條件說明這個rt節點對應區間的maxa==minb,說明更新該節點是對區間和有貢獻的,且rt節點是葉子節點
            {
                tree[rt].sum++;
                tree[rt].minb+=b[tree[rt].l];
                return ;
            }
    }
    ///執行下面的語句的話,說明rt節點不能成段更新或rt節點能成段更新,更新該節點對應的區間可能對區間和有貢獻。這2種情況都需要更新到rt的兒子
    pushdown(rt);
    int mid=(tree[rt].l+tree[rt].r)/2;
    if(mid>=r)
        update(l,r,ls);
    else
        if(mid+1<=l)
            update(l,r,rs);
        else
        {
            update(l,r,ls);
            update(l,r,rs);
        }
    pushup(rt);
}
ll query(int l,int r,int rt)
{
    if(tree[rt].l>=l&&tree[rt].r<=r)
    {
        return tree[rt].sum;
    }
    ll ans=0;
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(mid>=r)
        ans=query(l,r,ls);
    else
        if(mid+1<=l)
            ans=query(l,r,rs);
        else
        {
            ans=query(l,r,ls); 
            ans+=query(l,r,rs);

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

}