luogu P3521 [POI2011]ROT-Tree Rotations
题面传送门
考虑两颗子树如果交换,那么其实对其它子树与这两颗子树的贡献是没有影响的。
那么在线段树合并时判断一下是否要交换即可。
代码实现:
#include<cstdio>
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(now) f[now].l
#define r(now) f[now].r
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,root[400039],cnt,cntt,l[400039],r[400039],tot;
long long ans;
struct fhq{int l,r,f;}f[19000039];
inline void get(int x,int l,int r,int &now){
if(!now)now=++cntt;f[now].f++;
if(l==r)return;
int m=l+r>>1;
if(x<=m) get(x,l,m,l(now));
else get(x,m+1,r,r(now));
}
inline long long find(int x,int y,int w,int l,int r){
if(!x||!y){
if(!x) return 0;
else return f[x].f*w;
}
if(l==r)return f[x].f*w;
long long ans=0;int m=l+r>>1;
ans+=find(r(x),r(y),w,m+1,r)+find(l(x),l(y),w+f[r(y)].f,l,m);
return ans;
}
inline int merge(int x,int y,int l,int r){
if(!x||!y) return x+y;f[x].f+=f[y].f;
if(l==r)return x;
int m=l+r>>1;
l(x)=merge(l(x),l(y),l,m);r(x)=merge(r(x),r(y),m+1,r);
return x;
}
inline int dfs(int last){
int now=++cnt;
scanf("%d",&x);
if(!x){
l[now]=dfs(now);r[now]=dfs(now);
long long un=find(root[l[now]],root[r[now]],0,1,n),wn=find(root[r[now]],root[l[now]],0,1,n);
ans+=min(wn,un);
root[now]=merge(root[l[now]],root[r[now]],1,n);
}
else get(x,1,n,root[now]);
return now;
}
int main(){
// freopen("1.in","r",stdin);
register int i;
scanf("%d",&n);
dfs(0);
printf("%lld\n",ans);
}