【Luogu】P3521ROT-Tree Rotations(线段树合并)

  题目链接

  神奇的线段树合并qwq   不过就思路而言很好想……

  观察到一棵树无论怎么交换两棵左右子树,子树内部的最优逆序对并没影响……决策只影响左右子树之间的逆序对……

  于是线段树合并直接乱搞就好啦

  

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#define mid ((l+r)>>1)
#define check(x) if(x==0)    x=++tot;
#define maxn 400200
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

long long ls[maxn];
long long rs[maxn];
long long q[maxn];
long long root[maxn];
long long lc[maxn*10];
long long rc[maxn*10];
long long tree[maxn*10];
long long f[maxn];
long long c,w;
long long ans;
long long n,tot,cnt;

inline void pushup(long long rt){    tree[rt]=tree[lc[rt]]+tree[rc[rt]];    }

void update(long long o,long long l,long long r,long long &rt){
    check(rt);
    if(l==r){
        tree[rt]++;    return;
    }
    if(o<=mid)    update(o,l,mid,lc[rt]);
    else        update(o,mid+1,r,rc[rt]);
    pushup(rt);
}

void gettree(long long &x){
    x=++cnt;
    q[x]=read();
    if(q[x])    return;
    gettree(ls[x]);
    gettree(rs[x]);
    return;
}

long long merge(long long x,long long y){
    if(x==0)    return y;
    if(y==0)    return x;
    c+=tree[rc[x]]*tree[lc[y]];
    w+=tree[lc[x]]*tree[rc[y]];
    lc[x]=merge(lc[x],lc[y]);
    rc[x]=merge(rc[x],rc[y]);
    pushup(x);
    return x;
}

void calc(long long x){
    if(q[x])    return;
    calc(ls[x]);
    calc(rs[x]);
    c=w=0;
    root[x]=merge(root[ls[x]],root[rs[x]]);
    ans+=min(c,w);
    return;
}

void build(long long x){
    if(q[x]){
        update(q[x],1,n,root[x]);
        return;
    }
    build(ls[x]);
    build(rs[x]);
    return;
}

long long Root;

int main(){
    n=read();
    gettree(Root);
    build(1);
    calc(1);
    printf("%lld",ans);
    return 0;
}

 

posted @ 2018-01-27 08:13  Konoset  阅读(144)  评论(0编辑  收藏  举报