1269E K Integers(数据结构)
题意:
给一个1-n的排列,每进行一次操作可交换序列中相邻的两数,设 f ( k ) f(k) f(k)为使序列出现连续的1,2,…,k所需要的最小操作数,求所有的 f ( k ) , k = 1 , 2 , . . . , n ( n ≤ 2 ∗ 1 0 5 ) f(k),k=1,2,...,n\ (n\le 2*10^5) f(k),k=1,2,...,n (n≤2∗105)。
解法:
当一段长度为m的子序列为一个1-m的排列时,显然 f ( m ) f(m) f(m)为子序列中逆序对总个数。于是进一步考虑求 f ( k ) f(k) f(k)时,将1-k这k个数字”聚拢“成连续的一段所需要的操作数。可以证明,以位于最中间的数字为“中心”聚拢时交换次数最小。设1-k在原序列中的位置为 p 1 , p 2 , . . . , p k p_1,p_2,...,p_k p1,p2,...,pk,中心位置为 l l l, r = l + 1 r=l+1 r=l+1,整个序列被分为两部分: [ 1 , l ] 、 [ r , n ] [1,l]、[r,n] [1,l]、[r,n]。设位于 [ 1 , l ] [1,l] [1,l]的 p i p_i pi有 l c n t lcnt lcnt个,位于 [ r , n ] [r,n] [r,n]的 p i p_i pi有 r c n t rcnt rcnt个,则将位于 [ 1 , l ] [1,l] [1,l]的 p i p_i pi交换至 [ l − l c n t + 1 , l ] [l-lcnt+1,l] [l−lcnt+1,l],交换次数为 l ∗ l c n t − ∑ p i ≤ l p i − ( 1 + 2 + . . . + l c n t − 1 ) l*lcnt-\sum\limits_{p_i\le l} p_i-(1+2+...+lcnt-1) l∗lcnt−pi≤l∑pi−(1+2+...+lcnt−1),同理对 [ r , n ] [r,n] [r,n]中的 p i p_i pi交换次数为 ∑ p i ≥ r p i − r ∗ r c n t − ( 1 + 2 + . . . + r c n t − 1 ) \sum\limits_{p_i\ge r} p_i-r*rcnt-(1+2+...+rcnt-1) pi≥r∑pi−r∗rcnt−(1+2+...+rcnt−1)。
综上,我们只需在k从1到n递增的过程中动态维护 l 、 l c n t 、 ∑ p i ≤ l p i l、lcnt、\sum\limits_{p_i\le l} p_i l、lcnt、pi≤l∑pi。利用一个大根堆和一个小根堆可实现动态维护序列 p i p_i pi的中位数 l l l。再分别用两个树状数组 t r e e 1 、 t r e e 2 tree1、tree2 tree1、tree2维护 l c n t lcnt lcnt和 ∑ p i ≤ l p i \sum\limits_{p_i\le l} p_i pi≤l∑pi,修改时在位置 p i p_i pi上, t r e e 1 tree1 tree1每次增加1, t r e e 2 tree2 tree2每次增加 p i p_i pi。求逆序对数利用 t r e e 1 tree1 tree1即可。
复杂度: O ( n l o g n ) O(nlogn) O(nlogn)。
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn=2e5+5;
int n,p[maxn],idx[maxn];
ll tree1[maxn],tree2[maxn];
priority_queue<int>lhp;
priority_queue<int,vector<int>,greater<int> >rhp;
void update(int x,int val)
{ while(x<=n) tree1[x]++,tree2[x]+=val,x+=lowbit(x); }
ll query(int x,ll* tree)
{
ll ans=0;
while(x) ans+=tree[x],x-=lowbit(x);
return ans;
}
void insert(int x)
{
if(!rhp.empty()&&x>=rhp.top())
{
lhp.push(rhp.top());
rhp.pop(),rhp.push(x);
}
else lhp.push(x);
if(rhp.size()+1<lhp.size())
rhp.push(lhp.top()),lhp.pop();
}
ll sum(ll x)
{ return x*(x+1)/2; }
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>p[i],idx[p[i]]=i;
ll inv=0;
for(int i=1;i<=n;i++)
{
update(idx[i],idx[i]),insert(idx[i]);
int l=lhp.top(),r=l+1;
int lcnt=query(l,tree1),rcnt=i-lcnt;
inv+=i-query(idx[i],tree1);
ll ans=inv+query(n,tree2)-2*query(l,tree2);
ans+=l*lcnt-r*rcnt-sum(lcnt-1)-sum(rcnt-1);
cout<<ans<<" ";
}
}