Description
给定一棵二叉树,每个叶子上面有权值,你可以任意交换某个点的两颗子树
使得最后形成的树的中序遍历出来的子树的逆序对最少
(n le 2 imes10^5)
Solution
如果你真的想做这个题,请耐心手玩样例并看懂这个题神仙一样的输入方式……
考虑逆序对怎么构成的
从值域入手,然后其实答案就是
[min(sz[ls[x]] imes sz[rs[y]],sz[rs[x]] imes sz[ls[y]])
]
(这里直接搬了线段树合并的式子……)
然后我们对每个点值开权值线段树合并,查询的时候更新答案,然后向上合并信息即可
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=4e6+10;
int rt[N],ls[N],rs[N],sum[N],tot,n,cnt,ans;
inline void push_up(int x){return sum[x]=sum[ls[x]]+sum[rs[x]],void();}
inline void change(int &p,int l,int r,int v)
{
if(!p) p=++tot;
if(l==r) return sum[p]++,void();
int mid=(l+r)>>1;
if(v<=mid) change(ls[p],l,mid,v);
else change(rs[p],mid+1,r,v);
return push_up(p);
}
int r1,r2;
inline int merge(int x,int y)
{
if(!x||!y) return x+y;
r1+=sum[ls[x]]*sum[rs[y]]; r2+=sum[rs[x]]*sum[ls[y]];
ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); sum[x]+=sum[y];
return x;
}
inline int dfs()
{
int x=read();
if(x)
{
change(rt[++cnt],1,n,x);
return rt[cnt];
}
else
{
int tmp=merge(dfs(),dfs());
ans+=min(r1,r2); r1=0,r2=0; return tmp;
}
}
signed main()
{
n=read(); dfs(); printf("%lld
",ans);
return 0;
}
}
signed main(){return yspm::main();}
Review
这种好玩的题记得要观察性质
可以递归的就递归处理子问题