CF # 609E | + half Fenwick tree


Cf teammates made a title over, then. . One morning to do a question. .


CF # 609E address topics
review Fenwick tree beg number reverse 1
Review Fenwick tree beg number 2 reverse
the reference blog a
reference blog 2

Title effect: each neighboring node can move, able to find the minimum number of exchange 1 to k sequences appear

Ideas:
The minimum number of exchanges, first of all think about the number of reverse order, previously done similar questions, 321, switching to the minimum number of 123, is to find the number of reverse 321 of this sequence = 3
this question a little change , is the middle 321 may be other numbers, such as 34521, we seek to minimize the number of exchanges 32 1 occurs;
contemplated, 4 and 5, the removed, first 321 move together, then numbers by reverse; culling all final answer = 4,5 + value 321 times the number in reverse order.
Numbers by reverse order, sets Fenwick tree template on it.
So the focus is seeking remove happened exchange 4 and 5 extra element number, where is necessary to use two points, two points a minimum intermediate position determined optimum switching times, two points are the most suitable intermediate position, such that the left and right balance of the number of exchanges least.
Each number can be used and an intermediate position (position difference -1) to indicate the number of exchanges required, here a tree with another array, each record <= i and position to achieve the prefix is sum2 array.
So concludes:
build two Fenwick tree:
1.sum1 (i) represents the i-th position before maintenance there have been a number of smaller number than the current number of the number of
former representation 2.sum2 (i) i positions smaller than the number of all current positions and
3. half SUM2, sum formula, refer to the above blog 2

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 2e5+5;
ll sum1[maxn];
ll sum2[maxn];
ll a[maxn];
ll pos[maxn];
int n;


//树状数组模板 
ll lowbit(ll x){
    return x & -x;
} 
void add(ll *sum,ll x,ll v){
    while(x <= n){
        sum[x] += v;
        x += lowbit(x);
    }
}
ll query(ll *sum,ll x){
    ll res = 0;
    while(x > 0){
        res += sum[x];
        x -= lowbit(x);
    }
    return res;
} 

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        pos[a[i]] = i;//值为a[i]的元素 "位置"在为i的地方 
    }
    ll ans1 = 0;
    for(int i=1;i<=n;i++){
        ans1 += i - 1 - query(sum1,pos[i]); //求逆序数 和相加 
        add(sum1,pos[i],1); //前i个位置中已经出现了的比当前数要小的数的个数+1 
        add(sum2,pos[i],pos[i]); //比第i个位置小的 位置+pos[i] 
        int mid,l = 1,r = n;
        while(l<=r){ //二分需要靠拢的最中间的位置 
            mid = (l+r)>>1;
            if(query(sum1,mid)*2 <= i) l = mid+1;
            else r = mid - 1;
        }
        //将mid左边的数靠拢到mid附近的花费  
        //cnt:mid左边部分的个数 sum1(mid):维护的是前mid个元素的比mid小的元素个数(比mid小才需要移动) 
        //sum:mid前的位置和  sum2(mid)维护的是第mid个元素前的所有元素的位置和 
        ll ans2 = 0;
        ll cnt = query(sum1,mid);
        ll sum = query(sum2,mid);
        ans2 += mid*cnt-sum-cnt*(cnt-1)/2;
        //将mid右边的数靠拢到mid附近的花费 
        //cnt是每个mid右边的个数 sum = 总的所有元素位置和 - mid前位置和 = 右边元素位置和 
        cnt = i-cnt;
        sum = query(sum2,n) - sum;
        ans2 += sum-cnt*(mid+1)-cnt*(cnt-1)/2;
        cout<<ans1+ans2<<" ";
    }
    return 0;
} 

Guess you like

Origin www.cnblogs.com/fisherss/p/12106618.html