給出n個數,有m個詢問,每個詢問輸入l,r,求出l到r中的所有數通過與相鄰數交換變為上公升序列的交換次數
想不出來就用離線了
就想到用莫隊
然後對於操作的繼承,發現:
①在一列數的後面新增乙個數,逆序對數會增加數列中比它大的數的個數。
②在一列數的後面刪除乙個數,逆序對數會減少數列中比它大的數的個數。
③在一列數的前面新增乙個數,逆序對數會增加數列中比它小的數的個數。
④在一列數的前面刪除乙個數,逆序對數會減少數列中比它小的數的個數。
以上摳神犇部落格(因為我太懶了,發現了這些之後懶得寫。。)
設a[i]為當前l到r區間內》=i的數的個數,自然(r-l+1)-a[i]為當前l到r區間內
發現要區間修改值,原本想用線段樹,後來發現樹狀陣列差分可以做,就寫了樹狀陣列
我的**略醜,因為如果l
一把辛酸淚
#include#include#include
#include
#include
using
namespace
std;
typedef
long
long
ll;struct
lss[
51000
];struct
qnq[
51000
];int bk[51000
];bool
cmp(qn n1,qn n2)
bool
cmpd(qn n1,qn n2)
bool
lsd(ls n1,ls n2)
bool
lsid(ls n1,ls n2)
ll a[
51000
];int lowbit(int x)
intn;
ll getsum(
intx)
return
ans;
}void change(int
x,ll c)
}ll t[
51000
];int
main()
sort(s+1,s+n+1
,lsd);
for(int i=1;i<=n;i++) s[i].d=i;
sort(s+1,s+n+1
,lsid);
intm;
scanf("%d
",&m);
for(int i=1;i<=m;i++)
sort(q+1,q+m+1
,cmp);
int l=1,r=0
; ll ans=0
; memset(a,
0,sizeof
(a));
for(int i=1;i<=m;i++)
ans-=(r-l+1)-getsum(s[l].d);
change(
1,-1
);
if(s[l].d!=n) change(s[l].d+1,1
); l++;
}while(l>q[i].l)
ans+=(r-l+1)-getsum(s[l-1
].d);
l--;
change(
1,1);
if(s[l].d!=n) change(s[l].d+1,-1
); }
while(rans+=getsum(s[r+1
].d);
r++;
change(
1,1);
if(s[r].d!=n) change(s[r].d+1,-1
); }
while(r>q[i].r)
ans-=getsum(s[r].d)-1
; change(
1,-1
);
if(s[r].d!=n) change(s[r].d+1,1
); r--;
}q[i].d=ans;
}sort(q+1,q+m+1
,cmpd);
for(int i=1;i<=m;i++) printf("
%lld\n
",q[i].d);
return0;
}
bzoj3289 Mato的檔案管理
給定乙個序列,每次詢問乙個區間,你可以交換相鄰兩個元素,這個區間你最少需要多少次交換才能使其有序。我們觀察,每次交換如果交換a i 和a i 1 那麼顯然a i a i 1 交換後逆序對個數減一。當序列逆序對個數為0時序列就有序。那麼顯然題意就是詢問區間逆序對個數。我們可以用莫隊演算法來做。因為它符...
bzoj 3289 Mato的檔案管理
description mato同學從各路神犇以各種方式 你們懂的 收集了許多資料,這些資料一共有n份,每份有乙個大小和乙個編號。為了防止他人偷拷,這些資料都是加密過的,只能用mato自己寫的程式才能訪問。mato每天隨機選乙個區間 l,r 他今天就看編號在此區間內的這些資料。mato有乙個習慣,他...
bzoj3289 Mato的檔案管理
description mato同學從各路神犇以各種方式 你們懂的 收集了許多資料,這些資料一共有n份,每份有乙個大小和乙個編號。為了防止他人偷拷,這些資料都是加密過的,只能用mato自己寫的程式才能訪問。mato每天隨機選乙個區間 l,r 他今天就看編號在此區間內的這些資料。mato有乙個習慣,他...