1. 程式人生 > 實用技巧 >luogu P3521 [POI2011]ROT-Tree Rotations

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);
}