求调! 二分线段树,思路大概就是先二分找到能抗住的最大的那个2的次幂,再二分前缀和,时间复杂度 O(loglogn)。
大样例3最后跑出非常逆天的结果,有一段应该全是49648的,结果我跑出:
49648
49648
120000
105001
105001
102375
102001
102001
171011
99001
150000
96005
96005
96004
96004
96004
96004
96003
96003
96003
150000 ???
96003
49648
49648
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N=200005;
int n,q,W;
int a[N],pow2[64];
#define lson (x<<1)
#define rson (x<<1|1)
#define mid ((l+r)>>1)
#define ls l,mid,lson
#define rs mid+1,r,rson
int seg[N<<2],tag[N<<2];
void update(int x){
seg[x]=seg[lson]+seg[rson];
}
void build(int l,int r,int x){
tag[x]=0;
if(l==r){
seg[x]=a[l];
return;
}
build(ls);
build(rs);
update(x);
}
void pushdown(int l,int r,int x){
if(!tag[x]) return;
seg[lson]+=(mid-l+1)*tag[x];
seg[rson]+=(r-mid)*tag[x];
tag[lson]+=tag[x];
tag[rson]+=tag[x];
tag[x]=0;
}
void modify(int l,int r,int x,int L,int R,int k){
if(l>R||r<L) return;
if(L<=l&&r<=R){
seg[x]+=(r-l+1)*k;
tag[x]+=k;
return;
}
pushdown(l,r,x);
modify(ls,L,R,k);
modify(rs,L,R,k);
update(x);
}
int query(int l,int r,int x,int L,int R){
if(l>R||r<L) return 0;
if(L<=l&&r<=R){
return seg[x];
}
pushdown(l,r,x);
int ans=0;
ans+=query(ls,L,R);
ans+=query(rs,L,R);
return ans;
}
signed main(){
freopen("wxyt3.in","r",stdin);
freopen("wxyt.out","w",stdout);
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
pow2[0]=1;
for(int i=1;i<=63;i++){
pow2[i]=pow2[i-1]*2;
}
//cout<<pow2[63]<<endl;
cin>>n>>q>>W;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,n,1);
int rec=1e18;
while(q--){
int L,R,d;
cin>>L>>R>>d;
modify(1,n,1,L,R,d);
int l=1,r=63,k=0;
int sum=query(1,n,1,1,n);
while(l<=r){
int mi=(l+r)>>1;
if(W>sum*(pow2[mi]-1)){
l=mi+1;
k=mi;
}
else{
r=mi-1;
}
}
int w=W-sum*(pow2[k]-1);
l=1,r=n;
int pos=0;
while(l<=r){
int mi=(l+r)>>1;
int tmp=query(1,n,1,1,mi);
if(w>pow2[k]*tmp){
l=mi+1;
pos=mi;
}
else{
r=mi-1;
}
}
cout<<n*k+pos<<'\n';
}
}