题解 P3521 【[POI2011]ROT-Tree Rotations】
输入格式真的毒瘤
权值线段树合并。
我们先对每一个叶子建一棵权值线段树,并把它自己的权值插入到里面。然后不断的向上合并。
我们不妨设原树中当前节点为
而我们现在已经把
同理,无论我们交不交换
所以对于跨
我们遍历两棵权值线段树来暴力合并两棵权值线段树。
那么对于
同理,如果交换
最后合并完统计答案即可。
代码如下:
#include<bits/stdc++.h>
#define N 200010
#define int long long
using namespace std;
struct Tree
{
int ch[2],size;
}t[N<<5];
int n,tot,ans,num1,num2;
int update(int l,int r,int val)
{
int u=++tot;
t[u].size=1;
if(l==r) return u;
int mid=(l+r)>>1;
if(val<=mid) t[u].ch[0]=update(l,mid,val);
else t[u].ch[1]=update(mid+1,r,val);
return u;
}
int merge(int a,int b,int l,int r)//把b合并至a
{
if(!a||!b) return a+b;
if(l==r)
{
t[a].size+=t[b].size;
return a;
}
num1+=t[t[a].ch[1]].size*t[t[b].ch[0]].size;//不交换的答案
num2+=t[t[b].ch[1]].size*t[t[a].ch[0]].size;//交换后的答案
int mid=(l+r)>>1;
t[a].ch[0]=merge(t[a].ch[0],t[b].ch[0],l,mid);
t[a].ch[1]=merge(t[a].ch[1],t[b].ch[1],mid+1,r);
t[a].size+=t[b].size;
return a;
}
int dfs()
{
int u,val;
scanf("%lld",&val);
if(!val)
{
int lc=dfs(),rc=dfs();
num1=num2=0;
u=merge(lc,rc,1,n);
ans+=min(num1,num2);//ans加上较小值
}
else u=update(1,n,val);
return u;
}
signed main()
{
scanf("%lld",&n);
dfs();
printf("%lld\n",ans);
return 0;
}