题面
分析
区间加很裸
关键是怎么处理除的问题,很明显,不能用lazy,因为不能满足直接合并左右区间而得到大区间的答案
除的效果是会让数字变小,那么减法也可以做到,我们就把除法变成减法
当序列被除到一个比较小的数的时候,最后减去的数可以是相同的
比如 2 2 2 3 除以3,得到 0 0 0 1,相当于每个数减去了2.只需要维护序列中最大的数除后等效的减的值和最小的数除后等效减的值,如果一样,就进行区间减,修改lazy。
此题的坑点在于有负数,负数除法要手动向下取整
听起来挺暴力的,时间复杂度的证明不会,据说是均摊时间复杂度?
#include<bits/stdc++.h> using namespace std; #define N 201000 #define lc (p<<1) #define rc (p<<1|1) #define INF 0x7fffffff7fffffff #define mid (t[p].l+t[p].r>>1) #define INT int #define ll long long ll n,q; ll a[N]; struct email { ll l,r,minx,maxx,sum,lazy; }t[N*4]; inline ll divid(ll x,ll y) { return floor((double)x/y); } void pushnow(ll p,ll v) { t[p].lazy+=v; t[p].sum+=v*(t[p].r-t[p].l+1); t[p].maxx+=v; t[p].minx+=v; } void pushup(ll p) { t[p].maxx=max(t[lc].maxx,t[rc].maxx); t[p].minx=min(t[lc].minx,t[rc].minx); t[p].sum=t[lc].sum+t[rc].sum; } void pushdown(ll p) { if(t[p].lazy) { pushnow(lc,t[p].lazy); pushnow(rc,t[p].lazy); t[p].lazy=0; } } void build(ll p,ll l,ll r) { t[p].l=l,t[p].r=r; if(l==r) { t[p].lazy=0; t[p].sum=a[l]; t[p].minx=a[l]; t[p].maxx=a[l]; return ; } ll m=(l+r)>>1; build(lc,l,m);build(rc,m+1,r); pushup(p); } void update(ll p,ll ql,ll qr,ll v) { if(ql<=t[p].l&&qr>=t[p].r) { pushnow(p,v); return ; } pushdown(p); if(ql<=mid)update(lc,ql,qr,v); if(qr>mid)update(rc,ql,qr,v); pushup(p); } ll query_min(ll p,ll ql,ll qr) { ll ans=INF; if(ql<=t[p].l&&qr>=t[p].r) return t[p].minx; pushdown(p); if(ql<=mid)ans=min(ans,query_min(lc,ql,qr)); if(qr>mid)ans=min(ans,query_min(rc,ql,qr)); pushup(p); return ans; } ll query_sum(ll p,ll ql,ll qr) { ll ans=0; if(ql<=t[p].l&&qr>=t[p].r) return t[p].sum; pushdown(p); if(ql<=mid)ans+=query_sum(lc,ql,qr); if(qr>mid)ans+=query_sum(rc,ql,qr); pushup(p); return ans; } void divide(ll p,ll ql,ll qr,ll v) { if(ql<=t[p].l&&qr>=t[p].r) { ll delta1=t[p].maxx;delta1=delta1-divid(delta1,v); ll delta2=t[p].minx;delta2=delta2-divid(delta2,v); if(delta1==delta2) { pushnow(p,-delta1); return ; } } pushdown(p); if(ql<=mid)divide(lc,ql,qr,v); if(qr>mid)divide(rc,ql,qr,v); pushup(p); } INT main() { scanf("%lld%lld",&n,&q); for(ll i=0;i<n;i++) scanf("%lld",&a[i]); build(1,0,n-1); while(q--) { ll op; scanf("%lld",&op); if(op==1) { ll l,r,c; scanf("%lld%lld%lld",&l,&r,&c); update(1,l,r,c); } if(op==2) { ll l,r,c; scanf("%lld%lld%lld",&l,&r,&c); divide(1,l,r,c); } if(op==3) { ll l,r; scanf("%lld%lld",&l,&r); printf("%lld ",query_min(1,l,r)); } if(op==4) { ll l,r; scanf("%lld%lld",&l,&r); printf("%lld ",query_sum(1,l,r)); } } return 0; }