題目大意
給定一個序列b,以及一個初值爲0的序列a。要求支持a的區間+1以及區間詢問a[i]/b[i]的和。
題解
我們考慮對開一個線段樹,每個節點記錄當前a區間最大的值maxa
以及最小的值minb,區間當前情況下的a[i]/b[i]的和cnt,以及lazy標記修改a序列。
每次修改的時候修改maxa。如果當前葉子結點a[i]>=b[i]那麼就將b[i]+=b[i],cnt+1。一直等到a[i]再加到b[i]的時候纔會更新。
代碼
//hdu6315 Naive Operations
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#define lson l,mid,st<<1
#define rson mid+1,r,st<<1|1
#define N 100100
using namespace std;
struct Tree{int mxa,mnb,cnt,lazy;}tree[N<<4];
int b[N],n,m;
void pushup(int x)
{
tree[x].cnt=tree[x<<1].cnt+tree[x<<1|1].cnt;
tree[x].mnb=min(tree[x<<1].mnb,tree[x<<1|1].mnb);
tree[x].mxa=max(tree[x<<1].mxa,tree[x<<1|1].mxa);
}
void pushdown(int x)
{
if (tree[x].lazy==0) return;
int v=tree[x].lazy;tree[x].lazy=0;
tree[x<<1].lazy+=v;tree[x<<1|1].lazy+=v;
tree[x<<1].mxa+=v;tree[x<<1|1].mxa+=v;
}
void build(int l,int r,int st)
{
if (l==r) {tree[st].mnb=b[l];return;}
int mid=(l+r)>>1;
build(lson);build(rson);
pushup(st);
}
void update(int L,int R,int l,int r,int st)
{
if (L<=l&&r<=R)
{
tree[st].mxa++;
if (tree[st].mnb>tree[st].mxa){tree[st].lazy++;return;}
else
if (l==r&&tree[st].mnb<=tree[st].mxa)
{
tree[st].cnt++;
tree[st].mnb+=b[l];
return;
}
}
pushdown(st);
int mid=(l+r)>>1;
if (L<=mid) update(L,R,lson);
if (R>mid) update(L,R,rson);
pushup(st);
}
int query(int L,int R,int l,int r,int st)
{
if (L<=l&&r<=R) return tree[st].cnt;
int ret=0,mid=(l+r)>>1;
pushdown(st);
if (L<=mid) ret+=query(L,R,lson);
if (R>mid) ret+=query(L,R,rson);
return ret;
}
int main()
{
for (;~scanf("%d%d",&n,&m);)
{
memset(tree,0,sizeof(tree));
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
build(1,n,1);
for (int i=1;i<=m;i++)
{
char ch[6];int L,R;
scanf("%s%d%d",ch,&L,&R);
if (ch[0]=='a') update(L,R,1,n,1);
else printf("%d\n",query(L,R,1,n,1));
}
}
return 0;
}