[DS记录]P7447 [Ynoi2007] rgxsxrs

command_block

2021-06-28 21:29:13

Personal

**题意** : 给定一个长为 $n$ 的序列 $A$ ,进行 $m$ 次操作 : - 将区间 $[l,r]$ 中所有 $>x$ 的元素减去 $x$。 - 表示询问区间 $[l,r]$ 的和,最小值,最大值。 $n,m\leq 5\times 10^5,A_i\leq 10^9$ ,时限$\texttt{6s}$ ,空限$\texttt{64M}$。 ------------ 我们认为 $O(\log n)=O(\log A)$。 考虑倍增分块,倍数为 $B$ ,将值域分为形如 $[B^i,B^{i+1})$ 的 $O(\log_Bn)$ 个块。 对于每个块内的数,分别用线段树维护。需要维护区间最小值最大值以及和。 对第 $i$ 棵线段树修改时,分三类讨论 : - ① $a_{\max}\leq x$ : 操作没有影响,直接返回。 - ② $a_{\min}-x\geq B_i$ : 区间内减 $x$ 后仍然都在当前块内,打区间减标记即可。 - ③ 对于叶节点,$a-x<B_i$ :将其删除,加入下一层。 三类位置形成若干连续段,若段数为 $k$ ,则本次操作的复杂度为 $O(k\log n)$。 在 ③ 中,每个值只会下降 $O(\log_Bn)$ 次,这部分复杂度为 $O(n\log n\log_Bn)$。 其余的复杂度可以看做与 ② 的个数直接相关。 块内的总和至多是 $O(nB^{i+1})$ 的,每次修改中,若存在 ① 且 ② 生效 $k$ 次,则总和至少减少 $O(kB^i)$。 于是花费于 ② 的总复杂度是 $O(nB\log n)$ 的。 选取一个合适的 $B$ 可以做到 $O\big((n+m)\log^2n/\log\log n\big)$。 此时空间复杂度是 $O(n\log n/\log\log n)$ ,且常数较大,难以通过。 考虑底层进行 $O(\log)$ 分块,对小区间进行暴力,即可改进为 $O(n)$。 ```cpp #include<algorithm> #include<cstdio> #define ll long long #define MaxN 530000 using namespace std; namespace io { char buf[1<<22],*p1=buf,*p2=buf,obuf[5005000],*O=obuf; #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,(1<<22)-10,stdin),p1==p2)?EOF:*p1++) int rd() { int x=0;char ch=getchar(); while(ch<'0'||'9'<ch)ch=getchar(); while('0'<=ch&&ch<='9')x=x*10+(ch^48),ch=getchar(); return x; } void putc(char ch){*O++=ch;} void print(ll x){if(x>9)print(x/10);*O++=x%10+'0';} void flush(bool op=0){if (O-obuf>=5000000||op){fwrite(obuf,O-obuf,1,stdout);O=obuf;}} }using namespace io; const int BS=16,INF=1000000000 ,pw[9]={1,10,100,1000,10000,100000,1000000,10000000,100000000}; inline void glev(int x,int &p){while(pw[p]>x)p--;} int x[MaxN],lev[MaxN],st[MaxN],tn,slv[MaxN]; struct Node{ int x0,x1,c,tg;ll s; inline void ladd(int t) {tg+=t;x0+=t;x1+=t;s+=1ll*t*c;} }; int n,x0,x1;ll sum; struct SGT{ int lv; Node a[(MaxN/BS)<<1]; inline void up(int u){ a[u].x0=min(a[u<<1].x0,a[u<<1|1].x0); a[u].x1=max(a[u<<1].x1,a[u<<1|1].x1); a[u].s=a[u<<1].s+a[u<<1|1].s; a[u].c=a[u<<1].c+a[u<<1|1].c; } inline void build2(int l,int r,int u) { a[u].x0=INF;a[u].x1=a[u].s=a[u].c=0; for (int i=l;i<=r;i++){ if (lev[i]==-1&&slv[i]==lv)lev[i]=lv; if (lev[i]==lv){ a[u].x0=min(a[u].x0,x[i]); a[u].x1=max(a[u].x1,x[i]); a[u].c++;a[u].s+=x[i]; } } } void build(int l,int r,int u) { if (r-l+1<=BS){build2(l,r,u);return ;} int mid=(l+r)>>1; build(l,mid,u<<1); build(mid+1,r,u<<1|1); up(u); } inline void ladd(int u){ if (a[u].tg){ a[u<<1].ladd(a[u].tg); a[u<<1|1].ladd(a[u].tg); a[u].tg=0; } } inline void ladd2(int l,int r,int u){ if (!a[u].tg)return ; for (int i=l;i<=r;i++) if (lev[i]==lv)x[i]+=a[u].tg; a[u].tg=0; } int to; void upd(int l,int r,int u) { if (r-l+1<=BS){ladd2(l,r,u);build2(l,r,u);return ;} int mid=(l+r)>>1;ladd(u); if (to<=mid)upd(l,mid,u<<1); else upd(mid+1,r,u<<1|1); up(u); } void upd(int t){to=t;upd(1,n,1);} int wfl,wfr,wfc; void _sub(int l,int r,int u) { if (r-l+1<=BS){ ladd2(l,r,u); int tl=max(l,wfl),tr=min(r,wfr); for (int i=tl;i<=tr;i++)if (lev[i]==lv&&x[i]>wfc){ glev(x[i]-=wfc,lev[i]); if (lev[i]<lv)st[++tn]=i; }build2(l,r,u);return ; } if (a[u].x1<=wfc)return ; if (wfl<=l&&r<=wfr&&a[u].x0-wfc>=pw[lv]) {a[u].ladd(-wfc);return ;} int mid=(l+r)>>1;ladd(u); if (wfl<=mid)_sub(l,mid,u<<1); if (mid<wfr)_sub(mid+1,r,u<<1|1); up(u); } void sub(int l,int r,int x) {wfl=l;wfr=r;wfc=x;_sub(1,n,1);} void qry(int l,int r,int u) { if (r-l+1<=BS){ ladd2(l,r,u); l=max(l,wfl);r=min(r,wfr); for (int i=l;i<=r;i++)if (lev[i]==lv) {x0=min(x0,x[i]);x1=max(x1,x[i]);sum+=x[i];} return ; } if (wfl<=l&&r<=wfr){ x0=min(x0,a[u].x0); x1=max(x1,a[u].x1); sum+=a[u].s; return ; }int mid=(l+r)>>1;ladd(u); if (wfl<=mid)qry(l,mid,u<<1); if (mid<wfr)qry(mid+1,r,u<<1|1); } void qry(int l,int r) {wfl=l;wfr=r;qry(1,n,1);} }T[9]; int m; int main() { n=rd();m=rd(); for (int i=1;i<=n;i++) glev(x[i]=rd(),lev[i]=8); for (int i=0;i<9;i++) {T[i].lv=i;T[i].build(1,n,1);} int las=0; for (int i=1,op,l,r,x;i<=m;i++){ op=rd();l=rd()^las;r=rd()^las; if (op==1){ x=rd()^las; for (int k=0;k<=8;k++){ tn=0;T[k].sub(l,r,x); for (int j=1;j<=tn;j++) {slv[st[j]]=lev[st[j]];lev[st[j]]=-1;} for (int j=1;j<=tn;j++){ int p=st[j]; T[slv[p]].upd(p); } } }else { x0=INF;x1=sum=0; for (int k=0;k<=8;k++)T[k].qry(l,r); print(sum);putc(' '); print(x0);putc(' '); print(x1);putc('\n'); las=sum&((1<<20)-1); }flush(); }flush(1); return 0; } ```