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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【Luogu1393】动态逆序对(CDQ分治)

發布時間:2023/11/30 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Luogu1393】动态逆序对(CDQ分治) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【Luogu1393】動態逆序對(CDQ分治)

題面

題目描述

對于給定的一段正整數序列,我們定義它的逆序對的個數為序列中ai>aj且i < j的有序對(i,j)的個數。你需要計算出一個序列的逆序對組數及其刪去其中的某個數的逆序對組數。

輸入輸出格式

輸入格式:

第一行,兩個數n,m,表示序列中有n個數,要刪去m個數

第二行n個數,表示給定的序列。

第三行m個數,第i個數di表示要刪去原序列中的第di個數。

輸出格式:

一行m+1個數。第一個數表示給定序列的逆序對組數,第i+1個數表示刪去第di個數后序列的逆序對組數(刪去的數不再恢復)

輸入輸出樣例

輸入樣例#1:

6 3
5 4 2 6 3 1
2 1 4

輸出樣例#1:

11 7 4 2

說明

對于20%的數據,n≤2500

對于另30%的數據,m=0

對于100%的數據,n≤40000,m≤n/2,且保證第二行n個數互不相同,第三行m個數互不相同

題解

之前不是說過要寫一遍CDQ分治嗎??
在這里說的
可是,當你把上面的代碼興高采烈的Copy到洛谷上之后
你就會直接WA了
因為,題目還是有點不同的(仔細讀題)
區別一:這題不是排列,要離散化
區別二:這題刪掉的不是數字,而是位置

好了回歸正題,講講CDQ分治怎么寫
首先,給所有刪掉的數編個號,就按照刪去的順序來吧
沒有刪掉的數就編個INF吧

那么,刪掉這個數之后,減少的逆序對對數是:
對于\(j\in[1,j]\)
\(t[i]<t[j]\),其中t是刪除的編號
并且
\(i<j,a[i]>a[j]\)
或者
\(i>j,a[i]<a[j]\)
所以,刪除的編號直接sort搞完
剩下的兩維CDQ分治

于是,發現這個玩意是一個三維偏序
所以之前寫過的樹狀數組套平衡樹當然也可以做啦
但是,CDQ分治還是要會嗷。。

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define MAX 50000 inline int read() {int x=0,t=1;char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();if(ch=='-')t=-1,ch=getchar();while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*t; } int n,m,S[MAX],a[MAX],b[MAX],c[MAX],d[MAX]; long long ans; int lowbit(int x){return x&(-x);} void Add(int x,int w){while(x<=n)c[x]+=w,x+=lowbit(x);} int getsum(int x){int ret=0;while(x)ret+=c[x],x-=lowbit(x);return ret;} struct Node {int t,p,a;int s; }t[MAX]; bool operator<(Node a,Node b){return a.t<b.t;} bool cmp(Node a,Node b){return a.p<b.p;} void CDQ(int l,int r) {if(l==r)return;int mid=(l+r)>>1;CDQ(l,mid);CDQ(mid+1,r);sort(&t[l],&t[mid+1],cmp);sort(&t[mid+1],&t[r+1],cmp);int j=mid;for(int i=l;i<=mid;++i){while(j<r&&t[j+1].p<t[i].p)++j,Add(t[j].a,1);t[i].s+=getsum(n)-getsum(t[i].a);}for(int i=mid+1;i<=j;++i)Add(t[i].a,-1);j=r+1;for(int i=mid;i>=l;--i){while(j>mid+1&&t[j-1].p>t[i].p)--j,Add(t[j].a,1);t[i].s+=getsum(t[i].a-1);}for(int i=r;i>=j;--i)Add(t[i].a,-1); } int main() {n=read();m=read();for(int i=1;i<=n;++i)S[i]=a[i]=read();sort(&S[1],&S[n+1]);for(int i=1;i<=n;++i)b[a[i]=lower_bound(&S[1],&S[n+1],a[i])-S]=i;for(int i=n;i;i--)ans+=getsum(a[i]),Add(a[i],1);for(int i=1;i<=n;++i)t[i].t=n+1,t[i].p=i,t[i].a=a[i];for(int i=1;i<=m;++i){d[i]=read();t[d[i]].t=i;}sort(&t[1],&t[n+1]);memset(c,0,sizeof(c));CDQ(1,n);for(int i=1;i<=n;++i)c[t[i].p]=t[i].s;printf("%lld ",ans);for(int i=1;i<=m;++i)printf("%lld ",ans=ans-c[d[i]]);return 0; }

轉載于:https://www.cnblogs.com/cjyyb/p/8127824.html

總結

以上是生活随笔為你收集整理的【Luogu1393】动态逆序对(CDQ分治)的全部內容,希望文章能夠幫你解決所遇到的問題。

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