题目
长为n(n<=5e5)的数组a,第i个数ai(-1e9<=ai<=1e9)
q(q<=5e5)次操作,每次选择一个区间[l,r],对这个区间加x(-1e9<=x<=1e9)
求序列操作前及第[1,q]次操作后,这q+1次对应的序列中,
历史最小字典序是哪个序列,输出序列
实际为t(t<=5e5)组样例,sumn和sumq均不超过5e5
思路来源
夏老师代码
HHU_zZhu代码
题解1(在线)
在线就是直接考虑保留第几次操作后是最优答案
考虑已经有一个最优答案,怎么替换成一个更优的答案,
肯定是最优答案,从某个前缀位置开始,有一个单点减,使这个点变得更小了
那区间减也可以维护成若干个差分,
如果若干次操作后,差分的第一个位置是一个单点减,说明是可以替换成更优的答案
所以map维护区间差分的位置,把map上差分为0的项实时抹掉,
去判断第一个差分非0的最左项是正还是负的,是负的说明可以保留,更新答案
题解2(离线)
扫描线思想, 把[0,q]这q+1个时间戳拍到线段树上,让这q+1个位置同时从第一个位置开始比
n个位置,q个时刻,扫描线,增序扫n个位置,l加,r+1减
在扫描线区间内的位置,即被若干次修改覆盖,
在某个时间区间对应+x,另一个时间区间对应-y,...,
保留区间加对应的最小的那个时间区间
每个修改是有时间后效性的,也就是第i时刻的修改,会改[i,q]时间的值
只关注最小值即可,删掉不可能成为最小值的时刻,这些时刻一定是在前缀某个位置处变大了
维护区间最小值,删掉的置成INF,保证经过后面的操作这些也不可能成为最小即可
代码1(在线)
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<vector> #include<map> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);++i) #define per(i,a,b) for(int i=(a);i>=(b);--i) typedef long long ll; typedef double db; typedef pair<int,int> P; #define fi first #define se second #define pb push_back #define dbg(x) cerr<<(#x)<<":"<<x<<" "; #define dbg2(x) cerr<<(#x)<<":"<<x<<endl; #define SZ(a) (int)(a.size()) #define sci(a) scanf("%d",&(a)) #define pt(a) printf("%d",a); #define pte(a) printf("%d ",a) #define ptlle(a) printf("%lld ",a) #define debug(...) fprintf(stderr, __VA_ARGS__) using namespace std; const int N=5e5+10; map<int,ll>mp; array<int,3>op[N]; int t,n,q,pos,a[N],l,r,w; ll add[N]; int main(){ sci(t); while(t--){ sci(n); mp.clear(); pos=0; rep(i,1,n){ sci(a[i]); add[i]=0; } sci(q); rep(i,1,q){ sci(l),sci(r),sci(w); op[i]={l,r,w}; mp[l]+=w; mp[r+1]-=w; if(!mp[l])mp.erase(mp.find(l)); if(!mp[r+1])mp.erase(mp.find(r+1)); if(mp.size() && mp.begin()->se<0){ pos=i; mp.clear(); } } rep(i,1,pos){ auto [l,r,w]=op[i]; add[l]+=w; add[r+1]-=w; } rep(i,1,n){ add[i]+=add[i-1]; } rep(i,1,n){ printf("%lld%c",a[i]+add[i]," "[i==n]); } } return 0; }
代码2(离线)
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<vector> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);++i) #define per(i,a,b) for(int i=(a);i>=(b);--i) typedef long long ll; typedef double db; typedef pair<int,int> P; #define fi first #define se second #define pb push_back #define dbg(x) cerr<<(#x)<<":"<<x<<" "; #define dbg2(x) cerr<<(#x)<<":"<<x<<endl; #define SZ(a) (int)(a.size()) #define sci(a) scanf("%d",&(a)) #define pt(a) printf("%d",a); #define pte(a) printf("%d ",a) #define ptlle(a) printf("%lld ",a) #define debug(...) fprintf(stderr, __VA_ARGS__) using namespace std; const int N=5e5+10; const ll INF=1e18,INF2=1e17; typedef pair<int,int> P; struct segtree{ int n; struct node{int l,r;ll c,mn,mx;}e[N<<2]; #define l(p) e.l #define r(p) e.r #define mn(p) e.mn #define mx(p) e.mx #define c(p) e.c void up(int p){ mn(p)=min(mn(p<<1),mn(p<<1|1)); mx(p)=max(mx(p<<1),mx(p<<1|1)); } void bld(int p,int l,int r){ l(p)=l;r(p)=r; mn(p)=mx(p)=c(p)=0; if(l==r){return;} int mid=l+r>>1; bld(p<<1,l,mid);bld(p<<1|1,mid+1,r); up(p); } void psd(int p){ if(c(p)){ mn(p<<1)+=c(p); mx(p<<1)+=c(p); c(p<<1)+=c(p); mn(p<<1|1)+=c(p); mx(p<<1|1)+=c(p); c(p<<1|1)+=c(p); c(p)=0; } } void init(int _n){n=_n;bld(1,0,n);} void add(int p,int ql,int qr,int v){ if(mn(p)>=INF2)return; if(ql<=l(p)&&r(p)<=qr){ mn(p)+=v; mx(p)+=v; c(p)+=v; return; } psd(p); int mid=l(p)+r(p)>>1; if(ql<=mid)add(p<<1,ql,qr,v); if(qr>mid)add(p<<1|1,ql,qr,v); up(p); } void del(int p,int ql,int qr,ll v){// 每一个要删的递归到底,均摊O(nlogn) if(mn(p)>=INF2)return; if(l(p)==r(p) && mx(p)>v){ mn(p)=INF; mx(p)=-INF; return; } psd(p); int mid=l(p)+r(p)>>1; if(ql<=mid && mx(p<<1)>v)del(p<<1,ql,qr,v);// 左区间有要删的 if(qr>mid && mx(p<<1|1)>v)del(p<<1|1,ql,qr,v);// 右区间又要删的 up(p); } ll ask(int p,int ql,int qr){ if(mn(p)>=INF2)return INF2; if(ql<=l(p)&&r(p)<=qr)return mn(p); int mid=l(p)+r(p)>>1; ll res=INF2; psd(p); if(ql<=mid)res=min(res,ask(p<<1,ql,qr)); if(qr>mid)res=min(res,ask(p<<1|1,ql,qr)); return res; } }seg; int t,n,a[N],q,l,r,w; vector<P>add[N],del[N]; ll ans[N]; int main(){ sci(t); while(t--){ sci(n); rep(i,1,n){ sci(a[i]); add[i].clear(); del[i].clear(); } sci(q); seg.init(q); rep(i,1,q){ sci(l),sci(r),sci(w); add[l].pb(P(i,w)); del[r].pb(P(i,w)); } rep(i,1,n){ for(auto &x:add[i]){ //printf("i:%d x.fi:%d x.se:%d ",i,x.fi,x.se); seg.add(1,x.fi,q,x.se); } ll mn=seg.ask(1,0,q); ans[i]=mn+a[i]; seg.del(1,0,q,mn); for(auto &x:del[i]){ seg.add(1,x.fi,q,-x.se); } } rep(i,1,n){ printf("%lld%c",ans[i]," "[i==n]); } } return 0; }