其他分享
首页 > 其他分享> > BZOJ 2212: [Poi2011]Tree Rotations(线段树合并)

BZOJ 2212: [Poi2011]Tree Rotations(线段树合并)

作者:互联网

传送门

解题思路

  线段树合并,考虑交换两个子树时,对除这两棵子树外的其余点的逆序对不会造成影响,所以我们只需要贪心的使这两棵子树产生的逆序对最小。而考虑时我们也只需要考虑两棵子树间的逆序对数,不需要考虑每棵子树内部逆序对数,这样就非常好算了,可以线段树合并,合并的同时统计一下交换前和后的逆序对数,然后取个\(min\)加到答案里。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
const int N=200005;
typedef long long LL;

inline int rd(){
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?9:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;  
}

int n,tot,sum[N],ls[N],rs[N],pool[N],cur;
LL ans,res1,res2;

inline int newnode(){
    if(cur) return pool[cur--];
    return ++tot;   
}

int update(int l,int r,int pos){
    int now=newnode(); sum[now]=1; 
    if(l==r) return now; int mid=(l+r)>>1;
    if(pos<=mid) ls[now]=update(l,mid,pos);
    else rs[now]=update(mid+1,r,pos);
    sum[now]=sum[ls[now]]+sum[rs[now]];
    return now;
}

int merge(int u,int v,int l,int r){
    if(!u || !v) return (u|v);
    if(l==r) {sum[++tot]=sum[u]+sum[v]; return tot;}
    int mid=(l+r)>>1,now=newnode(); 
    res1+=(LL)sum[rs[u]]*sum[ls[v]],res2+=(LL)sum[ls[u]]*sum[rs[v]];
    ls[now]=merge(ls[u],ls[v],l,mid); rs[now]=merge(rs[u],rs[v],mid+1,r);
    sum[now]=sum[ls[now]]+sum[rs[now]]; pool[++cur]=u; pool[++cur]=v;
    return now;
}

int DFS(){
    int now=rd(),tmp,LS,RS;
    if(now) return update(1,n,now);
    LS=DFS(); RS=DFS(); tmp=merge(LS,RS,1,n);
    ans+=min(res1,res2); res1=res2=0;
    return tmp;
}

int main(){
    n=rd(); DFS();
    printf("%lld",ans);
    return 0;   
}

标签:2212,ch,rs,int,sum,Poi2011,Rotations,ls,now
来源: https://www.cnblogs.com/sdfzsyq/p/10350472.html