修改查詢 \(O(\sqrt n )-O(1)\) 平衡c++
而後對於 \(O(n\sqrt m)\) 次詢問形如 \([1,k]\) 與 \(r\) 的貢獻,咱們考慮掃描線,每次從 \([1,k]\) 擴展爲 \([1,k+1]\) ,這樣一共爲 \(n\) 次修改,而在過程當中咱們要進行 \(O(n\sqrt m)\) 詢問。而咱們能夠調整咱們維護數據結構的方式,使得每次擴展的複雜度爲 \(O( \sqrt m)\),而詢問的複雜度爲 \(O(1)\),從而達到平衡複雜度到 \(O(n\sqrt m)\) 級別。git
二次離線能夠經過差分將莫隊擴展區間變成總共 \(O(n)\) 次修改,\(O(n\sqrt m)\) 次查詢,就能夠平衡了。數據結構
首先要求 \([1,r-1]\) 與 \(r\) 的貢獻和 \([1,l-1]\) 與 \(r\) 的貢獻中 \([1,r-1]\) 與 \(r\) 必須預處理,而後全部 \([1,l-1]\) 與 \(r\) 的貢獻對應到每次莫隊區間擴展都對應着固定 \(l\),\(r\) 是一個連續的區間,變成 \(O(m)\) 個區間,能夠線性空間存儲,掃描線時每次 \(O(區間長度)\) 詢問便可,總共會詢問 \(O(n\sqrt m)\) 次,空間線性。spa
#include<bits/stdc++.h> using namespace std; #define LL long long #define debug(x) cerr<<#x<<" = "<<x #define sp <<" " #define el <<endl #define fgx cerr<<" -------------------------------------------------------- "<<endl #define LL long long #define DB double #define LDB long double #define pii pair<int,int> #define mp make_pair #define pb push_back inline int read(){ int nm=0; bool fh=true; char cw=getchar(); for(;!isdigit(cw);cw=getchar()) fh^=(cw=='-'); for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return fh?nm:-nm; } #define M 100020 #define B 330 int n,m,c[M],H[M],be[M],L[620],R[620],tot,tt1,tt2,d1,d2; LL pr[M],sf[M],S[M],ans[M],cur,A[M],W[620]; pii T[M]; inline void add(int k,int dt){for(;k<=n;k+=(k&-k))c[k]+=dt;} inline int qry(int k,int res=0){for(;k;k-=(k&-k))res+=c[k];return res;} struct Q{ int id,ls,rs; inline void gtin(int ID){id=ID,ls=read(),rs=read();} inline bool operator <(const Q&ot)const{ if(be[ls]!=be[ot.ls]) return be[ls]<be[ot.ls]; if(be[ls]&1) return rs<ot.rs; return rs>ot.rs; } }q[M]; struct _Q{ int kt,ps,to,ls,rs; _Q(){} _Q(int _kt,int _ps,int _to,int _ls,int _rs){kt=_kt,ps=_ps,to=_to,ls=_ls,rs=_rs;} }pre[M],suf[M]; bool cmp_pre(_Q a,_Q b){return a.ps<b.ps;} bool cmp_suf(_Q a,_Q b){return a.ps>b.ps;} inline void ins(int x){for(int k=be[x];k<=tot;k++)++W[k];for(int k=x,TP=R[be[x]];k<=TP;++k)++A[k];} inline int calc(int x){return W[be[x]-1]+A[x];} int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) H[i]=read(),T[i]=mp(H[i],i); sort(T+1,T+n+1); for(int i=1;i<=n;i++) H[T[i].second]=i; LL Now=0; for(L[tot=1]=1,R[tot]=B;R[tot]<n;++tot,L[tot]=R[tot-1]+1,R[tot]=R[tot-1]+B); R[tot]=n; for(int i=1;i<=n;i++) be[i]=(i-1)/B+1; for(int i=1;i<=n;i++) Now+=i-1-qry(H[i]),add(H[i],1),pr[i]=Now; for(int i=1;i<=n;i++) add(H[i],-1),sf[i]=Now,Now-=qry(H[i]); for(int i=1;i<=m;i++) q[i].gtin(i); sort(q+1,q+m+1); for(int l=1,r=1,i=1;i<=m;i++){ if(r<q[i].rs) S[i]+=pr[q[i].rs]-pr[r],pre[++tt1]=_Q(-1,l-1,i,r+1,q[i].rs),r=q[i].rs; if(l>q[i].ls) S[i]+=sf[q[i].ls]-sf[l],suf[++tt2]=_Q(-1,r+1,i,q[i].ls,l-1),l=q[i].ls; if(r>q[i].rs) S[i]-=pr[r]-pr[q[i].rs],pre[++tt1]=_Q(1,l-1,i,q[i].rs+1,r),r=q[i].rs; if(l<q[i].ls) S[i]-=sf[l]-sf[q[i].ls],suf[++tt2]=_Q(1,r+1,i,l,q[i].ls-1),l=q[i].ls; } sort(pre+1,pre+tt1+1,cmp_pre),sort(suf+1,suf+tt2+1,cmp_suf),d1=d2=1; while(d1<=tt1&&(!pre[d1].ps)) ++d1; while(d2<=tt2&&suf[d2].ps>n) ++d2; for(int i=1;i<=n&&d1<=tt1;i++) for(ins(H[i]);d1<=tt1&&pre[d1].ps==i;S[pre[d1].to]+=(LL)pre[d1].kt*(LL)(pre[d1].rs-pre[d1].ls+1)*(LL)i,++d1) for(int k=pre[d1].ls;k<=pre[d1].rs;++k) S[pre[d1].to]-=pre[d1].kt*calc(H[k]); memset(A,0,sizeof(A)),memset(W,0,sizeof(W)); for(int i=n;i>0&&d2<=tt2;--i) for(ins(H[i]);d2<=tt2&&suf[d2].ps==i;++d2) for(int k=suf[d2].ls;k<=suf[d2].rs;++k) S[suf[d2].to]+=suf[d2].kt*calc(H[k]); for(int i=1;i<=m;i++) cur+=S[i],ans[q[i].id]=cur; for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }