首页 > 其他 > 详细

BZOJ2212 Poi2011Tree Rotations(线段树合并)

时间:2018-07-29 13:51:48      阅读:136      评论:0      收藏:0      [点我收藏+]

显然子树内的操作不会对子树外产生影响。于是贪心,若交换之后子树内逆序对减少就交换。

这个东西可以用权值线段树计算。操作完毕后需要对两棵权值线段树合并,这个的复杂度是两棵线段树的重复节点个数。那么总复杂度不太显然的是O(nlogn)。因为相当于把n个只有一个叶子的线段树合并在一起。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 400010
int n,cnt=0,tot=0,root[N];
long long ans=0,ansl,ansr;
struct data{int l,r,x;}tree[N<<5];
void add(int &k,int l,int r,int x)
{
    if (!k) k=++cnt;
    tree[k].x++;
    if (l==r) return;
    int mid=l+r>>1;
    if (x<=mid) add(tree[k].l,l,mid,x);
    else add(tree[k].r,mid+1,r,x);
}
int merge(int x,int y,int l,int r)
{
    if (!x||!y) return x|y;
    ansl+=1ll*tree[tree[x].l].x*tree[tree[y].r].x;
    ansr+=1ll*tree[tree[x].r].x*tree[tree[y].l].x;
    tree[x].x+=tree[y].x;
    int mid=l+r>>1;
    tree[x].l=merge(tree[x].l,tree[y].l,l,mid),
    tree[x].r=merge(tree[x].r,tree[y].r,mid+1,r);
    return x;
}
int get()
{
    int x=read(),t=++tot;
    if (x) add(root[t],1,n,x);
    else 
    {
        int l=get(),r=get();
        ansl=0,ansr=0;
        root[t]=merge(root[l],root[r],1,n);
        ans+=min(ansl,ansr);
    }
    return t;
}
int main()
{
    freopen("bzoj2212.in","r",stdin);
    freopen("bzoj2212.out","w",stdout);
    n=read();
    get();
    cout<<ans;
    fclose(stdin);fclose(stdout);
    return 0;
}

 

BZOJ2212 Poi2011Tree Rotations(线段树合并)

原文:https://www.cnblogs.com/Gloid/p/9384878.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!