Luogu3521/BZOJ2212 POI2011 Tree rotations 线段树合并

传送门——Luogu

传送门——BZOJ


叶子节点的权值两两不同,考虑线段树合并进行统计。

首先有一个显然的贪心策略:如果在某一个节点处,交换左右子树会使得这一棵子树内的逆序对个数更少,就一定要交换,因为现在交不交换对以后的状态不会产生影响。

然后我们考虑如何计算交换或者不交换的逆序对数量。对于一棵子树中的一个数来说,以它为右端的逆序对数就是另一棵子树中比它大的数,这类似于线段树中的查询前缀和的操作。这种统计操作也是线段树合并很擅长的。

具体代码段如下

int merge(int p , int q){
    if(!p)
        return q;
    if(!q)
        return p;
    Tree[p].size += Tree[q].size;
    ans1 += 1ll * Tree[Tree[p].l].size * Tree[Tree[q].r].size;
    ans2 += 1ll * Tree[Tree[q].l].size * Tree[Tree[p].r].size;
//ans1表示交换,ans2表示不交换
    Tree[p].l = merge(Tree[p].l , Tree[q].l);
    Tree[p].r = merge(Tree[p].r , Tree[q].r);
    throwaway(q);//节点回收
    return p;
}

中间的ans1和ans2的统计应该也是不难理解的。

#include<bits/stdc++.h>
#define mid ((l + r) >> 1)
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    bool f = 0;
    char c = getchar();
    while(c != EOF && !isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    while(c != EOF && isdigit(c)){
        a = (a << 3) + (a << 1) + (c ^ '0');
        c = getchar();
    }
    return f ? -a : a;
}

const int MAXN = 200010;
struct node{
    int l , r , size;
}Tree[MAXN * 20];
int root[MAXN << 1] , N , cntNode , cnt;
long long ans , ans1 , ans2;
queue < int > trashbin;

inline int allocate(){
    if(trashbin.empty())
        return ++cntNode;
    int t = trashbin.front();
    trashbin.pop();
    return t;
}

inline void throwaway(int now){
    Tree[now].l = Tree[now].r = Tree[now].size = 0;
    trashbin.push(now);
}

void insert(int& now , int l , int r , int tar){
    if(!now)
        now = allocate();
    ++Tree[now].size;
    if(l != r)
        if(mid >= tar)
            insert(Tree[now].l , l , mid , tar);
        else
            insert(Tree[now].r , mid + 1 , r , tar);
}

int merge(int p , int q){
    if(!p)
        return q;
    if(!q)
        return p;
    Tree[p].size += Tree[q].size;
    ans1 += 1ll * Tree[Tree[p].l].size * Tree[Tree[q].r].size;
    ans2 += 1ll * Tree[Tree[q].l].size * Tree[Tree[p].r].size;
    Tree[p].l = merge(Tree[p].l , Tree[q].l);
    Tree[p].r = merge(Tree[p].r , Tree[q].r);
    throwaway(q);
    return p;
}

void create(int now){
    int t = read();
    if(!t){
        int p = ++cnt;
        create(p);
        root[now] = root[p];
        create(p = ++cnt);
        merge(root[now] , root[p]);
        ans += min(ans1 , ans2);
        ans1 = ans2 = 0;
    }
    else
        insert(root[now] , 1 , N , t);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("3521.in" , "r" , stdin);
    //freopen("3521.out" , "w" , stdout);
#endif
    N = read();
    create(1);
    printf("%lld" , ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10069507.html