链接
题解
这题据说是线段树合并板子题…
其实我觉得也不是特别的板,逆序对处理的地方还是要思考一下…(也可能是我太菜了)
整体做法是看一下交换子树和不交换子树的代价哪个更小。
问题就是怎么统计这个量呢?
网上的很多代码都是直接在线段树合并的同时去计算这两个量,但是我把线段树合并写成了一个结构体,原则上不太像改变封装内部的东西。所以我就每次只扫描较小的那一颗子树,查询另一棵对应的线段树中的一些信息,这样复杂度类似启发式合并,是 O ( n l o g n ) O(nlogn) O(nlogn)的。
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 200010
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
struct joinable_segment_tree
{
int sum[maxn*18*2], ch[maxn*18*2][2], tot;
void clear(){tot=0;}
int New(int v=0)
{
tot++;
sum[tot]=v;
ch[tot][0]=ch[tot][1]=0;
return tot;
}
int create(int l, int r, int pos, int v) //创建一条链
{
int ret=New(v), o=ret;
while(l<r)
{
int mid(l+r>>1);
if(pos<=mid)o=ch[o][0]=New(v), r=mid;
else o=ch[o][1]=New(v), l=mid+1;
}
return ret;
}
int join(int u, int v)
{
if(!u or !v)return u|v;
auto t=New(sum[u]+sum[v]);
ch[t][0]=join(ch[u][0],ch[v][0]);
ch[t][1]=join(ch[u][1],ch[v][1]);
return t;
}
int qsum(int o, int l, int r, int L, int R) //在[L,R]里查[l,r]的和
{
int mid(L+R>>1), ans(0);
if(l<=L and r>=R)return sum[o];
if(l<=mid)ans+=qsum(ch[o][0],l,r,L,mid);
if(r>mid)ans+=qsum(ch[o][1],l,r,mid+1,R);
return ans;
}
}mori;
ll ans=0;
int n, v[maxn], tot;
int dfs()
{
int x=read();
if(x)return mori.create(1,n,v[++tot]=x,+1);
else
{
int now=tot, tot1, tot2;
int t1, t2, ret;
t1=dfs(); tot1=tot;
t2=dfs(); tot2=tot;
ret=mori.join(t1,t2);
ll cnt1=0, cnt2=0;
if(tot1-now<tot2-tot1)
for(int i=now+1;i<=tot1;i++)
cnt1+=mori.qsum(t2,1,v[i],1,n),
cnt2+=mori.qsum(t2,v[i],n,1,n);
else
for(int i=tot1+1;i<=tot2;i++)
cnt1+=mori.qsum(t1,1,v[i],1,n),
cnt2+=mori.qsum(t1,v[i],n,1,n);
ans += min(cnt1,cnt2);
return ret;
}
}
int main()
{
n=read();
dfs();
cout<<ans;
return 0;
}