题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=2212
思路
显然,一棵子树内的交换情况,并不会影响 这个子树与其他子树之间 的逆序对个数。
对每个点建一棵权值线段树,用线段树统计逆序对,然后搜索,搜到一个点,就把他的左右儿子代表的线段树合并,并计算左右儿子逆序对个数。
代码
#include <cstdio>
#include <algorithm>
const int maxn=
400000;
const int maxd=
4000000;
int read()
{
int x=
0,f=
1;
char ch=getchar();
while((ch<
'0')||(ch>
'9'))
{
if(ch==
'-')
{
f=-f;
}
ch=getchar();
}
while((ch>=
'0')&&(ch<=
'9'))
{
x=x*
10+ch-
'0';
ch=getchar();
}
return x*f;
}
struct node
{
node* son[
2];
int sum;
};
node* root[maxn+
10];
node tnode[maxd+
10];
int ls[maxn+
10],rs[maxn+
10],tot,n,cnt,val[maxn+
10],num,fa[maxn+
10];
long long ans,na,nb;
inline int updata(node* now)
{
now->sum=
0;
if(now->son[
0]!=NULL)
{
now->sum+=now->son[
0]->sum;
}
if(now->son[
1]!=NULL)
{
now->sum+=now->son[
1]->sum;
}
return 0;
}
node* build(node* now,
int l,
int r,
int v)
{
if(l==r)
{
now->son[
0]=now->son[
1]=NULL;
now->sum=
1;
return 0;
}
int mid=(l+r)>>
1;
if(v<=mid)
{
build(now->son[
0]=&tnode[++cnt],l,mid,v);
now->son[
1]=NULL;
}
else
{
now->son[
0]=NULL;
build(now->son[
1]=&tnode[++cnt],mid+
1,r,v);
}
updata(now);
return 0;
}
node* merge(node* a,node* b,
int l,
int r)
{
if(a==NULL)
{
return b;
}
if(b==NULL)
{
return a;
}
int mid=(l+r)>>
1;
if((a->son[
1]!=NULL)&&(b->son[
0]!=NULL))
{
na+=
1ll*a->son[
1]->sum*b->son[
0]->sum;
}
if((a->son[
0]!=NULL)&&(b->son[
1]!=NULL))
{
nb+=
1ll*a->son[
0]->sum*b->son[
1]->sum;
}
a->son[
0]=merge(a->son[
0],b->son[
0],l,mid);
a->son[
1]=merge(a->son[
1],b->son[
1],mid+
1,r);
updata(a);
return a;
}
inline int ins(
int a,
int b)
{
if(ls[a]!=
0)
{
rs[a]=b;
}
else
{
ls[a]=b;
}
fa[b]=a;
return 0;
}
int search(
int u)
{
if(ls[u]!=
0)
{
search(ls[u]);
search(rs[u]);
na=nb=
0;
root[u]=merge(root[ls[u]],root[rs[u]],
1,n);
ans+=
std::min(na,nb);
}
return 0;
}
int main()
{
n=read();
int w=
0,now=
0;
while(w<n)
{
val[++num]=read();
if(num>
1)
{
while(rs[now])
{
now=fa[now];
}
ins(now,num);
}
if(val[num])
{
++w;
}
else
{
now=num;
}
}
for(
int i=
1; i<=num; ++i)
{
if(val[i])
{
build(root[i]=&tnode[++cnt],
1,n,val[i]);
}
}
search(
1);
printf(
"%lld\n",ans);
return 0;
}