把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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);
}
posted @ 2020-12-31 20:20  275307894a  阅读(43)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end