P3521 [POI2011]ROT-Tree Rotations

线段树合并怎么那么水。。。我以为是比较高深的东西。。。。。

对每个子树维护一棵动态开点的值域线段树,资磁线段树合并

合并子树的顺序对于上面没有影响,所以每一层合并都要取最小值

然后根据线段树的优秀性质,只要在merge的时候每个节点都算一下跨过mid的逆序对数(类似分治的思想),计入两种情况的ans

用两个ans的min更新总的Ans

#include<bits/stdc++.h>
#define il inline
#define vd void
#define rg register
typedef long long ll;
il char gc(){
    static char buf[233333],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,233333,stdin),p1==p2)?EOF:*p1++;
}
il int gi(){// fread读入优化
    char ch=gc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=gc();
    while(ch>='0'&&ch<='9')sum=sum*10+(ch^48),ch=gc();
    return sum;
}
int n;
ll ans=0,sum1=0,sum2=0;
int ls[10000019],rs[10000019],sum[10000019],id;
il int newnode(rg int x){
    rg int ret=++id,y=ret,l=1,r=n;
    sum[ret]=1;
    while(l!=r){
        rg int md=(l+r)>>1;
        if(x<=md)ls[y]=++id,y=ls[y],sum[y]=1,r=md;
        else rs[y]=++id,y=rs[y],sum[y]=1,l=md+1;
    }
    return ret;
}
il int merge(rg int x,rg int y){
    if(x==0||y==0)return x|y;
    sum1+=1ll*sum[ls[x]]*sum[rs[y]];
    sum2+=1ll*sum[rs[x]]*sum[ls[y]];
    sum[x]+=sum[y];
    ls[x]=merge(ls[x],ls[y]);
    rs[x]=merge(rs[x],rs[y]);
    return x;
}
il int solve(){
    rg int x=gi();
    if(x)return newnode(x);
    else{
        int l=solve(),r=solve();
        sum1=sum2=0;
        int ret=merge(l,r);
        ans+=std::min(sum1,sum2);
        return ret;
    }
}
int main(){
    n=gi();
    solve();
    printf("%lld\n",ans);
    return 0;
}

吐槽:

loj上数据好多了。。。

posted @ 2018-08-05 12:27  菜狗xzz  阅读(307)  评论(1编辑  收藏  举报