Portal
Title
Give you an array that does not rise initially, two kinds of queries:
- 1 xy: assign each ai of 1≤i≤x to max(ai,y);
- 2 xy: traverse from x to n, if ai ≤ y, then y subtract ai, make a contribution, and then traverse down. Output the final contribution sum.
answer
Obviously, after each 1 operation, the array still does not rise, and a breakpoint i ≤ x must be found, the number before i remains unchanged, and the numbers after it all become y.
Then the segment tree can be established, the first two points to find a breakpoint, then
the i + 1 ~ x assigned to Y;
For the 2 operation, the violent idea should be to find an interval (l, r), the sum of the interval just does not exceed y, and then subtract the interval sum from y, and then find the first point whose value does not exceed y from r+1, and then Extends to an interval and an interval that just does not exceed y...
Because of the line segment tree, the complexity of finding the interval and the complexity of finding the point are both equal , and the remaining trouble to us is how many times y will be subtracted.
Interval and is set , apparently
≤
, since
just not exceeded
, there is
and
≤
, can be obtained
, that is, each
at least by half, so reducing the number of times is not exceeded
,
Total complexity
I was too anxious, looking at the title, thinking that it was a waste of time to allow a certain interval to be modified.······
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define MAXN 200005
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
return f?x:-x;
}
int n,q,N;
ll a[MAXN],f[MAXN<<2],lz[MAXN<<2],rt[MAXN<<2];
struct node{
int x;ll y;
node(){}
node(int X,ll Y){x=X,y=Y;}
};
inline void build(int x,int l,int r){
if(l==r){f[x]=rt[x]=a[l],lz[x]=0;return;}
int mid=(l+r)>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
f[x]=f[x<<1]+f[x<<1|1],rt[x]=rt[x<<1|1],lz[x]=0;
}
inline void pushdown(int x,int l,int r){
if(lz[x]>0){
int mid=(l+r)>>1;
if(l<r)lz[x<<1]=lz[x<<1|1]=rt[x<<1]=rt[x<<1|1]=lz[x],f[x<<1]=lz[x]*(mid-l+1),f[x<<1|1]=lz[x]*(r-mid);
lz[x]=0;
}
}
inline void change(int x,int l,int r,int a,int b,ll w){
if(a>b)return;
if(l==a&&r==b){lz[x]=rt[x]=w,f[x]=w*(r-l+1);return;}
pushdown(x,l,r);
int mid=(l+r)>>1;
if(a<=mid)change(x<<1,l,mid,a,min(mid,b),w);
if(b>mid)change(x<<1|1,mid+1,r,max(a,mid+1),b,w);
f[x]=f[x<<1]+f[x<<1|1],rt[x]=rt[x<<1|1];
}
inline int findc(int x,int l,int r,int a,int b,ll w){//找点
if(l==r){
if(f[x]<=w)return l;
else return r+1;
}
pushdown(x,l,r);
int mid=(l+r)>>1;
if(l==a&&r==b){
if(rt[x<<1]<=w)return findc(x<<1,l,mid,l,mid,w);
else return findc(x<<1|1,mid+1,r,mid+1,r,w);
}
if(a<=mid){
int u=findc(x<<1,l,mid,a,min(mid,b),w);
if(u>min(mid,b)&&b>mid)return findc(x<<1|1,mid+1,r,max(a,mid+1),b,w);
else return u;
}
else return findc(x<<1|1,mid+1,r,a,b,w);
}
inline node findd(int x,int l,int r,int a,int b,ll s){//找区间
if(l==a&&r==b&&f[x]<=s)return node(b,f[x]);
if(l==r)return node(l-1,0);
pushdown(x,l,r);
int mid=(l+r)>>1;
node u=node(l-1,0),v=node(mid,0);
if(a<=mid){
u=findd(x<<1,l,mid,a,min(mid,b),s);
if(b>mid&&u.x==mid)v=findd(x<<1|1,mid+1,r,mid+1,b,s-u.y);
if(u.x==mid)return node(v.x,u.y+v.y);
else return u;
}
else return findd(x<<1|1,mid+1,r,a,b,s);
}
int main()
{
n=read(),q=read(),N=sqrt(n);
for(int i=1;i<=n;i++)a[i]=read();
build(1,1,n);
while(q--){
int opt=read(),x=read();ll y=read();
if(opt==1){
int o=findc(1,1,n,1,x,y);
change(1,1,n,o,x,y);
}
else{
int ans=0;
for(int i=x;i<=n;i++){
node o=findd(1,1,n,i,n,y);
if(o.x>=i)ans+=o.x-i+1,y-=o.y,i=o.x;
else i=findc(1,1,n,i,n,y)-1;
}
printf("%d\n",ans);
}
}
return 0;
}