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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P3157


題目大意

一個長度為nnn序列,每次刪除一個數,求刪除前的逆序對數量。


解題思路

時光倒流之后,我們變為每次加入一個數求逆序對數量。

我們將加入一個數的貢獻分為后面和前面兩部分
后面是加入時后方比他小的數的個數
前面是加入時前方比他大的數的個數

這里用aia_iai?表示加入的時間先后,bib_ibi?表示位置,cic_ici?表示數值

若只考慮后方,我們可以發現加入xxxiii有貢獻當且僅當
[ai≤ax&bi>bx&ci<cx][a_i\leq a_x\ \&\ b_i>b_x\ \&\ c_i<c_x][ai?ax??&?bi?>bx??&?ci?<cx?]

然后可以發現這是一個三維偏序問題,我們用CDQ+CDQ+CDQ+樹狀數組維護。

做兩次分別計算前后的貢獻就可以了

時間復雜度O(nlog?2n)O(n\log^2 n)O(nlog2n)


codecodecode

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e5+10; struct node{ll a,b,c; }a[N]; ll n,m,ans[N],loc[N]; struct Tree_Array{#define lowbit(x) (x&-x)ll t[N];void Change(ll x,ll z){while(x<=n){t[x]+=z;x+=lowbit(x);}}ll Ask(ll x){ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;}#undef lowbit(x) }T; bool cmp_a(node x,node y){if(x.a!=y.a) return x.a<y.a;return (x.b==y.b)?(x.c<y.c):(x.b<y.b); } bool cmp_zb(node x,node y) {return (x.b==y.b)?(x.c<y.c):(x.b<y.b);} bool cmp_fb(node x,node y) {return (x.b==y.b)?(x.c>y.c):(x.b>y.b);} void Cdq(ll l,ll r){if(l==r) return;ll mid=(l+r)>>1;Cdq(l,mid);Cdq(mid+1,r);sort(a+l,a+mid+1,cmp_zb);sort(a+mid+1,a+r+1,cmp_zb);ll k=l;for(ll i=mid+1;i<=r;i++){while(k<=mid&&a[k].b<=a[i].b)T.Change(a[k].c,1),k++;ans[a[i].a]+=T.Ask(a[i].c);}for(ll i=l;i<k;i++)T.Change(a[i].c,-1);return; } void Cdp(ll l,ll r){if(l==r) return;ll mid=(l+r)>>1;Cdp(l,mid);Cdp(mid+1,r);sort(a+l,a+mid+1,cmp_fb);sort(a+mid+1,a+r+1,cmp_fb);ll k=l;for(ll i=mid+1;i<=r;i++){while(k<=mid&&a[k].b>=a[i].b)T.Change(n-a[k].c+1,1),k++;ans[a[i].a]+=T.Ask(n-a[i].c+1);}for(ll i=l;i<k;i++)T.Change(n-a[i].c+1,-1);return; } int main() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;i++)scanf("%lld",&a[i].c),a[i].b=i,loc[a[i].c]=i,a[i].b=n-a[i].b+1;for(ll i=1,x;i<=m;i++)scanf("%lld",&x),a[loc[x]].a=m-i;sort(a+1,a+1+n,cmp_a);Cdq(1,n);sort(a+1,a+1+n,cmp_a);Cdp(1,n);for(ll i=1;i<m;i++)ans[i]+=ans[i-1];for(ll i=m-1;i>=0;i--)printf("%lld\n",ans[i]); }

總結

以上是生活随笔為你收集整理的P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】的全部內容,希望文章能夠幫你解決所遇到的問題。

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