P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】
正題
題目鏈接:https://www.luogu.com.cn/problem/P3157
題目大意
一個(gè)長(zhǎng)度為nnn序列,每次刪除一個(gè)數(shù),求刪除前的逆序?qū)?shù)量。
解題思路
時(shí)光倒流之后,我們變?yōu)槊看渭尤胍粋€(gè)數(shù)求逆序?qū)?shù)量。
我們將加入一個(gè)數(shù)的貢獻(xiàn)分為后面和前面兩部分
后面是加入時(shí)后方比他小的數(shù)的個(gè)數(shù)
前面是加入時(shí)前方比他大的數(shù)的個(gè)數(shù)
這里用aia_iai?表示加入的時(shí)間先后,bib_ibi?表示位置,cic_ici?表示數(shù)值
若只考慮后方,我們可以發(fā)現(xiàn)加入xxx時(shí)iii有貢獻(xiàn)當(dāng)且僅當(dāng)
[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?]
然后可以發(fā)現(xiàn)這是一個(gè)三維偏序問題,我們用CDQ+CDQ+CDQ+樹狀數(shù)組維護(hù)。
做兩次分別計(jì)算前后的貢獻(xiàn)就可以了
時(shí)間復(fù)雜度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]); }總結(jié)
以上是生活随笔為你收集整理的P3157-[CQOI2011]动态逆序对【CDQ分治,树状数组】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Max(原 HBO Max)现有订阅用户
- 下一篇: 爱国者推出星璨小岚机箱:双面玻璃无立柱,