[摸鱼]cdq分治 学习笔记
待我玩會游戲整理下思緒(分明是想摸魚
cdq分治是一種用于降維和處理對不同子區間有貢獻的離線分治算法
對于常見的操作查詢題目而言,時間總是有序的,而cdq分治則是耗費\(O(logq)\)的代價使動態操作化為靜態查詢問題(the world!
考慮無修改的求逆序對問題
每個元素可定義為\((pos_i,val_i)\),求對每個\((pos_i,val_i)\)有多少個\((pos_j,val_j)\),滿足\(pos_j<pos_i,val_j>val_i\)
cdq分治的過程就是令其中一維有序(pos),計算出貢獻消除該維度的影響,后面對已遍歷的元素只需得知\(val\)的關系即可
因此對于歸并過程的merge中假設\([l,mid]\)和\([mid+1,r]\)的子區間已經統計完,保證了兩個子區間分別有序,那只需再求左子區間對右子區間的貢獻即可
比如左子區間中的下標\(p\)和右子區間中的下標\(q\)滿足\(val_p>val_q\),那么可以得出\(val_{[p...mid]}>val_q\),左區間對于右區間中的\(q\)的貢獻為\(mid-p+1\),統計完后繼續維護大區間的有序并pushup即可
而對于有修改(既存在時間變量)的操作,我們需要維護左子區間的修改對右區間查詢的影響(因為對于分治,左區間存在是右區間存在的前提),對于查詢則需要標記時間的維度\(ansid\)
注意如果\(p\)和\(q\)優先越界的處理上的不同
以及區間查詢時一分為二的做法
練手題 Luogu - P3374
題意:m次操作,單點更新,區間查詢
我們把原數組的初始值當作插入修改來處理,時間復雜度\(O((m+n)log(m+n))\)
#include<bits/stdc++.h> #define rep(i,j,k) for(register int i=j;i<=k;i++) #define rrep(i,j,k) for(register int i=j;i>=k;i--) #define erep(i,u) for(register int i=head[u];~i;i=nxt[i]) #define print(a) printf("%lld",(ll)(a)) #define printbk(a) printf("%lld ",(ll)(a)) #define println(a) printf("%lld\n",(ll)(a)) using namespace std; const int MAXN = 1.5e6+11; typedef long long ll; const ll MOD = 1e9+7; const ll INF = 1ll<<60; unsigned int SEED = 19260817; ll read(){ll x=0,f=1;register char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f; }struct QUERY{int pos,val,type;bool operator < (const QUERY &rhs) const{if(pos!=rhs.pos) return pos<rhs.pos;return type<rhs.type;} }Q[MAXN],tmp[MAXN]; ll ans[MAXN]; void solve(int l,int r){if(l==r)return;int mid=l+r>>1;solve(l,mid);solve(mid+1,r);int p=l,q=mid+1,cnt=0;ll sum=0;while(p<=mid&&q<=r){if(Q[p]<Q[q]){if(Q[p].type==1) sum+=Q[p].val;tmp[++cnt]=Q[p++];}else{if(Q[q].type==2) ans[Q[q].val]-=sum;if(Q[q].type==3) ans[Q[q].val]+=sum;tmp[++cnt]=Q[q++];}}while(p<=mid) tmp[++cnt]=Q[p++];while(q<=r){if(Q[q].type==2) ans[Q[q].val]-=sum;if(Q[q].type==3) ans[Q[q].val]+=sum;tmp[++cnt]=Q[q++];}rep(i,1,cnt) Q[i+l-1]=tmp[i]; } int main(){int m,n;while(cin>>n>>m){int cnt=0,ansid=0;rep(i,1,n){Q[++cnt].pos=i;Q[cnt].val=read();Q[cnt].type=1;}rep(i,1,m){int op=read();if(op==1){Q[++cnt].pos=read();Q[cnt].val=read();Q[cnt].type=1;}else{int l=read();int r=read();Q[++cnt].pos=l-1;Q[cnt].val=++ansid;Q[cnt].type=2;Q[++cnt].pos=r;Q[cnt].val=ansid;Q[cnt].type=3;}}solve(1,cnt);rep(i,1,ansid) println(ans[i]);}return 0; }轉載于:https://www.cnblogs.com/caturra/p/9387626.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[摸鱼]cdq分治 学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: visio业务流程图教学_用visio软
- 下一篇: java使用手册_java配置使用手册