BZOJ 2212 [Poi2011]Tree Rotations

题解:交换某节点的两棵子树仅对   此节点子树对答案的贡献   有影响

Dfs,启发式合并时顺便求逆序对即可,贪心交不交换

O(nlogn*logn)

Noname讲过一种合并Treap求逆序对,仅需O(nlogn),还不会

注意:插入时维护路径上的siz,插入完Splay到根节点的儿子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=300009;

int n;
long long ans;

int nn;
int fa[maxn],ch[maxn][2],siz[maxn],ky[maxn];
inline int son(int x){
	if(ch[fa[x]][0]==x)return 0;
	else return 1;
}
void pushup(int x){
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}

inline void Rotate(int x){
	int y=fa[x];
	int z=fa[y];
	int b=son(x),c=son(y);
	int a=ch[x][b^1];
	if(z)ch[z][c]=x;
	fa[x]=z;
	if(a)fa[a]=y;
	ch[y][b]=a;
	fa[y]=x;ch[x][b^1]=y;
	pushup(y);pushup(x);
}

void Splay(int x,int i){
	while(fa[x]!=i){
		int y=fa[x];
		int z=fa[y];
		if(z==i){
			Rotate(x);
		}else{
			if(son(x)==son(y)){
				Rotate(y);Rotate(x);
			}else{
				Rotate(x);Rotate(x);
			}
		}
	}
}

int Ins(int p,int root){
	int ret=0;
	int x=root,y=0;
	while(x){
		siz[x]++;
		y=x;
		if(ky[p]>ky[x]){
			ret+=siz[ch[x][0]]+1;
			x=ch[x][1];
		}else{
			x=ch[x][0];
		}
	}
	x=p;
	fa[x]=y;ch[x][0]=ch[x][1]=0;siz[x]=1;
	if(y){
		if(ky[x]>ky[y])ch[y][1]=x;
		else ch[y][0]=x;
	}
	Splay(x,root);
	return ret;
}

long long Mer(int x,int root){
	long long ret=0;
	int rs=ch[x][1];
	if(ch[x][0])ret+=Mer(ch[x][0],root);
	ret+=Ins(x,root);
	if(rs)ret+=Mer(rs,root);
	return ret;
}

//int Getsmall(int val,int root){
//	int ret=0,x=root;
//	while(x){
//		if(val>ky[x]){
//			ret+=siz[ch[x][0]]+1;
//			x=ch[x][1];
//		}else{
//			x=ch[x][0];
//		}
//	}
//	return ret;
//}

//long long Tong(int x,int root){
//	long long ret=0;
//	ret=Getsmall(ky[x],root);
//	if(ch[x][0])ret+=Tong(ch[x][0],root);
//	if(ch[x][1])ret+=Tong(ch[x][1],root);
//	return ret;
//}

int Dfs(){
	int r;
	scanf("%d",&r);
	if(r){
		++nn;
		fa[nn]=ch[nn][0]=ch[nn][1]=0;
		ky[nn]=r;siz[nn]=1;
		return nn;
	}else{
		int x=Dfs();
		int y=Dfs();
		long long tm=0,tm2=0;
		long long sizx=siz[x];
		long long sizy=siz[y];
		if(siz[x]<siz[y]){
			tm=Mer(x,y)-sizx*(sizx-1)/2;
			tm2=sizx*sizy-tm;
			ans+=min(tm,tm2);
		}else{
			tm=sizx*sizy-(Mer(y,x)-sizy*(sizy-1)/2);
			tm2=sizx*sizy-tm;
			ans+=min(tm,tm2);
		}
		Splay(x,0);
		return x;
	}
}

int main(){
	scanf("%d",&n);
	Dfs();
	printf("%lld
",ans);
	return 0;
}

  

自己还是太辣鸡了
原文地址:https://www.cnblogs.com/zzyer/p/8481101.html