题解:P11217 【MX-S4-T1】「yyOI R2」youyou 的垃圾桶
非常明显的一道线段树二分题。
每场战斗前的强化就相当于区间加操作。
我们先对整个区间进行整体操作,计算 youyou 被所有垃圾桶攻击一遍后剩余血量,并用
当 youyou 的血量不足以支撑被全部垃圾桶攻击时,直接在线段树上二分,查找最多还能被攻击几次。
细节看代码。
CODE
#include<bits/stdc++.h>
#include<cstdio>
#define LL long long
#define N 222222
#define pushup(now) sum[now]=sum[now<<1]+sum[now<<1|1]
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
using namespace std;
LL n,q,W;
LL sum[N<<2],add[N<<2];
void build(LL l,LL r,LL now){
if(l==r){
sum[now]=read();
return ;
}
LL mid=l+r>>1;
build(l,mid,now<<1);build(mid+1,r,now<<1|1);
pushup(now);
return ;
}
void Add(LL l,LL r,LL now,LL v){
sum[now]+=(r-l+1)*v;
add[now]+=v;
return ;
}
void pushdown(LL l,LL r,LL now){
if(!add[now])return ;
LL mid=l+r>>1;
Add(l,mid,now<<1,add[now]);
Add(mid+1,r,now<<1|1,add[now]);
add[now]=0;
return ;
}
void modify(LL l,LL r,LL now,LL x,LL y,LL v){
if(l>=x&&r<=y)return Add(l,r,now,v);
LL mid=l+r>>1;
pushdown(l,r,now);
if(x<=mid)modify(l,mid,now<<1,x,y,v);
if(y>mid)modify(mid+1,r,now<<1|1,x,y,v);
pushup(now);
return ;
}
int main(){
// freopen("wxyt4.in","r",stdin);
// freopen("wxyt.out","w",stdout);
n=read();q=read();W=read();
build(1,n,1);
while(q--){
LL l=read(),r=read(),d=read(),w=W,ans=0,now=1,k=1;
modify(1,n,1,l,r,d);
while(w>sum[1]*k){
w-=sum[1]*k;
ans+=n;
k<<=1;
}
//以下为线段树二分
l=1,r=n;
while(l!=r){
LL mid=l+r>>1;
pushdown(l,r,now);//注意在此处下传懒标记
if(sum[now<<1]*k<w)ans+=mid-l+1,w-=sum[now<<1]*k,l=mid+1,now=now<<1|1;
else r=mid,now<<=1;
}
printf("%lld\n",ans);
}
return 0;
}