题目描述
题解
好像很久以前有一个神人写过什么证明说n个logn的链(线段树上)合并起来复杂度是nlogn的?
那么空间复杂度不会超过时间复杂度?
总逆序对数=左子树逆序对数+右子树逆序对数+左子树对右子树的影响
分别计算交换之前交换之后的然后再判断换不换
计算某一个子树对另一个子树的影响与这两个子树内部的顺序无关
如何计算一个子树对另一个子树的影响?
分别对这两个子树建立权值线段树
将这两个权值线段树合并
合并的过程中累加右子树(l,mid)*左子树(mid+1,r)即为影响
这样自底向上合并就可以了
正确性?
显然。。。
相当于每一次划分一个分界点,统计跨越这个分界点的贡献
第一次做这样的题,涨姿势
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 400005
int n,r,cnt,sz;
int ch[N][2],val[N];
int root[N],ls[N*30],rs[N*30];
LL sum[N*30];
LL ans,ansl,ansr;
void read(int &now)
{
now=++cnt;
scanf("%d",&val[now]);
if (!val[now])
{
read(ch[now][0]);
read(ch[now][1]);
}
}
void update(int now)
{
sum[now]=sum[ls[now]]+sum[rs[now]];
}
void insert(int &now,int l,int r,int x)
{
int mid=(l+r)>>1;
now=++sz;
if (l==r)
{
sum[now]=1;
return;
}
if (x<=mid) insert(ls[now],l,mid,x);
else insert(rs[now],mid+1,r,x);
update(now);
}
int merge(int x,int y)
{
if (!x) return y;
if (!y) return x;
ansl+=sum[rs[x]]*sum[ls[y]];
ansr+=sum[ls[x]]*sum[rs[y]];
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
update(x);
return x;
}
LL dfs(int x)
{
LL ans=0;
if (!val[x])
{
ans=dfs(ch[x][0])+dfs(ch[x][1]);
ansl=ansr=0;
root[x]=merge(root[ch[x][0]],root[ch[x][1]]);
ans+=min(ansl,ansr);
}
else insert(root[x],1,n,val[x]);
return ans;
}
int main()
{
scanf("%d",&n);
read(r);
ans=dfs(1);
printf("%lld\n",ans);
}