對於給定的一段正整數序列,我們定義它的逆序對的個數為序列中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
∈[1,
j] t
[i]j]
,其中t是刪除的編號
並且 i
a[i]
>a[
j]或者
i>j,
a[i]
j]所以,刪除的編號直接sort搞完
剩下的兩維cdq分治
於是,發現這個玩意是乙個三維偏序
所以之前寫過的樹狀陣列套平衡樹當然也可以做啦
但是,cdq分治還是要會嗷。。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define max 50000
inline
int read()
int n,m,s[max],a[max],b[max],c[max],d[max];
long
long ans;
int lowbit(int x)
void add(int x,int w)
int getsum(int x)
struct node
t[max];
bool
operator
<(node a,node b)
for(int i=mid+1;i<=j;++i)add(t[i].a,-1);
j=r+1;
for(int i=mid;i>=l;--i)
for(int i=r;i>=j;--i)add(t[i].a,-1);
}int main()
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;}
LG1393 動態逆序對
洛谷 cdq 分治,按照時間來分治 應為乙個刪除不能對前面的操作貢獻,所以考慮乙個刪除操作對它後面時間的操作的貢獻 用上乙個答案減去次貢獻即可 include include include include include include include using namespace std na...
動態逆序對
容易寫掛 對於新手與蒟蒻 洛谷 cdq 如果按照三維偏序那樣求,那麼會漏掉一些情況。所以要跑兩遍cdq。兩遍cdq又會有乙個問題,就是判等於的問題。第一遍cdq第三維判等於,第二遍判不等於.include define ll long long using namespace std inline ...
動態逆序對
題目鏈結 對於序列a,它的逆序對數定義為滿足iaj的數對 i,j 的個數。給1到n的乙個排列,按照某種順序依次刪 除m個元素,你的任務是在每次刪除乙個元素之前統計整個序列的逆序對數 input 輸入第一行包含兩個整數n和m,即初始元素的個數和刪除的元素個數。以下n行每行包含乙個1到n之間的正整數,即...