日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

模板:CDQ分治

發布時間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模板:CDQ分治 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
  • 例題
    • P3810 【模板】三維偏序(陌上花開)
    • P2487 [SDOI2011]攔截導彈

所謂CDQ分治,就是和由Conprour、Doctorjellyfish、QE添一同發明的分治算法

(逃)

前言

神奇的亂搞黑科技
CDQ分治能夠通過更小的時間常數和更簡單的代碼難度完爆一些大算法,如樹套樹、splay凸包等。
應用條件:詢問離線,修改獨立

例題

P3810 【模板】三維偏序(陌上花開)

有n個元素,每個元素有三個特征值,元素a大于元素b當且僅當a的三個特征值都大于等于b
設 f(i) 表示a大于的元素數量(不含自己),對于每一個 i ,求出 f(x)=i 的 x 的數目
n≤2×105n\le 2\times10^5n2×105

CDQ分治的經典套路:先遞歸求左右內部貢獻,再求左右對互相的貢獻
先按照x排序,然后每次合并的時候兩邊分別按照y排序,利用雙指針維護樹狀數組累加答案即可
時間復雜度O(nlog?2n)O(n\log^2n)O(nlog2n)
細節上,注意完全相同的元素需要特殊處理,樹狀數組不要忘記清空

#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) const int N=2e5+100; const int mod=998244353; inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; }int n,m,k; struct node{int a,b,c,id,w; }p[N],P[N]; bool cmpa(node u,node v){if(u.a!=v.a) return u.a<v.a;else if(u.b!=v.b) return u.b<v.b;return u.c<v.c; } bool cmpb(node u,node v){if(u.b!=v.b) return u.b<v.b;else return u.c<v.c; }int f[N]; inline void add(int p,int w){for(;p<=m;p+=p&-p) f[p]+=w;return; } inline int ask(int p){int res(0);for(;p;p-=p&-p) res+=f[p];return res; }int ans[N],bac[N]; void solve(int l,int r){if(l==r) return;int mid=(l+r)>>1;solve(l,mid);solve(mid+1,r);//printf("\nsolve:(%d %d)\n",l,r);sort(p+l,p+mid+1,cmpb);sort(p+mid+1,p+r+1,cmpb);int pl=l;for(int i=mid+1;i<=r;i++){while(pl<=mid&&p[pl].b<=p[i].b){add(p[pl].c,p[pl].w);//printf(" add: (%d %d %d) w=%d\n",p[pl].a,p[pl].b,p[pl].c,p[pl].w);++pl;}ans[p[i].id]+=ask(p[i].c);//printf(" query: (%d %d %d) add=%d\n",p[i].a,p[i].b,p[i].c,ask(p[i].c));}for(int i=l;i<pl;i++) add(p[i].c,-p[i].w);return; } int main(){ #ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout); #endifn=read();m=read();for(int i=1;i<=n;i++){P[i]=(node){(int)read(),(int)read(),(int)read()};}sort(P+1,P+1+n,cmpa);int tot(0);for(int i=1;i<=n;i++){if(i>1&&P[i-1].a==P[i].a&&P[i-1].b==P[i].b&&P[i-1].c==P[i].c) p[tot].w++;else{p[++tot]=P[i];p[tot].w=1;p[tot].id=tot;}}swap(tot,n);solve(1,n);for(int i=1;i<=n;i++){bac[ans[p[i].id]+p[i].w-1]+=p[i].w;//printf("(%d %d %d) ans=%d\n",p[i].a,p[i].b,p[i].c,ans[p[i].id]);}for(int i=0;i<tot;i++) printf("%d\n",bac[i]);return 0; } /* */

P2487 [SDOI2011]攔截導彈

某國為了防御敵國的導彈襲擊,發展出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度、并且能夠攔截任意速度的導彈,但是以后每一發炮彈都不能高于前一發的高度,其攔截的導彈的飛行速度也不能大于前一發。某天,雷達捕捉到敵國的導彈來襲。由于該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。
在不能攔截所有的導彈的情況下,我們當然要選擇使國家損失最小、也就是攔截導彈的數量最多的方案。但是攔截導彈數量的最多的方案有可能有多個,如果有多個最優方案,那么我們會隨機選取一個作為最終的攔截導彈行動藍圖。
我方間諜已經獲取了所有敵軍導彈的高度和速度,你的任務是計算出在執行上述決策時,每枚導彈被攔截掉的概率。

利用CDQ分治優化1D-1D的DP
先遞歸處理出左半區間的dp值,然后嘗試用左半區間的dp值更新右半區間,再遞歸處理右半區間
利用樹狀數組維護前/后綴最大值保證復雜度
時間復雜度O(nlog?2n)O(n\log^2n)O(nlog2n)
注意:在遞歸處理右半區間之前,需要先按照下標重新sort一下使右半區間重新變得有序

#include<bits/stdc++.h> using namespace std; #define ll __int128 #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) const int N=2e5+100; const int mod=1e9; inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; }int n,m,k; int q[N],cnt; struct node{int a,b,id;bool operator < (const node o){return a>o.a;} }p[N]; bool cmp(node u,node v){return u.id<v.id; } struct Dp{int val;ll num; }dp1[N],dp2[N]; void operator += (Dp &a,Dp b){if(b.val>a.val) a=b;else if(b.val==a.val) a.num+=b.num;return; }Dp f[N]; inline void Upd(int p,Dp w){for(;p<=cnt;p+=p&-p) f[p]+=w;return; } inline Dp Ask(int p){Dp res=(Dp){0,0};for(;p;p-=p&-p) res+=f[p];return res; } inline void Clear(int p){for(;p<=cnt;p+=p&-p) f[p]=(Dp){0,0};return; } void solve2(int l,int r){if(l==r){++dp2[l].val;return;}int mid=(l+r)>>1;solve2(mid+1,r);//printf("\nsolve: (%d %d)\n",l,r);sort(p+l,p+mid+1);sort(p+mid+1,p+r+1);int pl=r;for(int i=mid;i>=l;i--){while(pl>mid&&p[pl].a<=p[i].a){Upd(p[pl].b,dp2[p[pl].id]);//printf(" add: i=%d DP:(%d %d)\n",p[pl].id,dp2[pl].val,(int)dp2[pl].num);--pl;}dp2[p[i].id]+=Ask(p[i].b);//printf(" update: i=%d DP:(%d %d)\n",p[i].id,dp2[i].val,(int)dp2[i].num);}for(int i=r;i>pl;i--) Clear(p[i].b);sort(p+l,p+mid+1,cmp);solve2(l,mid);return; }inline void upd(int p,Dp w){p=cnt-p+1;for(;p<=cnt;p+=p&-p) f[p]+=w;return; } inline Dp ask(int p){p=cnt-p+1;Dp res=(Dp){0,0};for(;p;p-=p&-p) res+=f[p];return res; } inline void clear(int p){p=cnt-p+1;for(;p<=cnt;p+=p&-p) f[p]=(Dp){0,0};return; } void solve1(int l,int r){if(l==r){++dp1[l].val;return;}int mid=(l+r)>>1;solve1(l,mid);sort(p+l,p+mid+1);sort(p+mid+1,p+r+1);//printf("\nsolve: (%d %d)\n",l,r);int pl=l;for(int i=mid+1;i<=r;i++){while(pl<=mid&&p[pl].a>=p[i].a){upd(p[pl].b,dp1[p[pl].id]);++pl;//printf(" add: i=%d DP:(%d %d)\n",p[i].id,dp1[i].val,(int)dp1[i].num);}dp1[p[i].id]+=ask(p[i].b);//printf(" update: i=%d DP:(%d %d)\n",p[i].id,dp1[i].val,(int)dp1[i].num);}for(int i=l;i<pl;i++) clear(p[i].b);sort(p+mid+1,p+r+1,cmp);solve1(mid+1,r);return; }int main(){ #ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout); #endifn=read();for(int i=1;i<=n;i++){p[i].a=read();p[i].b=read();p[i].id=i;dp1[i].num=dp2[i].num=1;q[++cnt]=p[i].a;q[++cnt]=p[i].b;}sort(q+1,q+1+cnt);cnt=unique(q+1,q+1+cnt)-q-1;for(int i=1;i<=n;i++){p[i].a=lower_bound(q+1,q+1+cnt,p[i].a)-q;p[i].b=lower_bound(q+1,q+1+cnt,p[i].b)-q;}solve1(1,n);sort(p+1,p+1+n,cmp);solve2(1,n);ll sum=0;int ans(0);for(int i=1;i<=n;i++){if(dp1[i].val>ans){ans=dp1[i].val;sum=dp1[i].num;}else if(dp1[i].val==ans){sum+=dp1[i].num;}}printf("%d\n",ans);for(int i=1;i<=n;i++){//printf("i=%d dp1=(%d %d) dp2=(%d %d)\n",i,dp1[i].val,(int)dp1[i].num,dp2[i].val,(int)dp2[i].num);if(dp1[i].val+dp2[i].val-1==ans){printf("%.5lf ",1.0*dp1[i].num*dp2[i].num/sum);}else printf("0.00000 ");}return 0; } /* 10 23 7 63 14 84 57 40 74 96 79 20 27 48 37 86 70 66 28 86 47 */

總結

以上是生活随笔為你收集整理的模板:CDQ分治的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。