码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu3521 [POI2011]ROT-Tree Rotations

时间:2020-07-13 09:17:09      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:交换   sdi   class   name   ==   line   c++   线段   dfs   

Description

link

给定一棵二叉树,每个叶子上面有权值,你可以任意交换某个点的两颗子树

使得最后形成的树的中序遍历出来的子树的逆序对最少

\(n \le 2\times10^5\)

Solution

如果你真的想做这个题,请耐心手玩样例并看懂这个题神仙一样的输入方式……

考虑逆序对怎么构成的

从值域入手,然后其实答案就是

\[\min(sz[ls[x]]\times sz[rs[y]],sz[rs[x]]\times sz[ls[y]]) \]

(这里直接搬了线段树合并的式子……)

然后我们对每个点值开权值线段树合并,查询的时候更新答案,然后向上合并信息即可

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k==‘-‘) f=-1;
		while(isdigit(k)) res=res*10+k-‘0‘,k=getchar();
		return res*f;
	}
	const int N=4e6+10;
	int rt[N],ls[N],rs[N],sum[N],tot,n,cnt,ans;
	inline void push_up(int x){return sum[x]=sum[ls[x]]+sum[rs[x]],void();}
	inline void change(int &p,int l,int r,int v)
	{
		if(!p) p=++tot;
		if(l==r) return sum[p]++,void();
		int mid=(l+r)>>1;
		if(v<=mid) change(ls[p],l,mid,v);
		else change(rs[p],mid+1,r,v);
		return push_up(p);
	}
	int r1,r2;
	inline int merge(int x,int y)
	{
		if(!x||!y) return x+y;
		r1+=sum[ls[x]]*sum[rs[y]]; r2+=sum[rs[x]]*sum[ls[y]];
		ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); sum[x]+=sum[y];
		return x;
	}
	inline int dfs()
	{
		int x=read();
		if(x) 
		{
			change(rt[++cnt],1,n,x);
			return rt[cnt];
		}
		else 
		{
			int tmp=merge(dfs(),dfs());
			ans+=min(r1,r2); r1=0,r2=0; return tmp;
		}
	}
	signed main()
	{
		n=read(); dfs(); printf("%lld\n",ans); 
		return 0;
	}
}
signed main(){return yspm::main();} 

Review

这种好玩的题记得要观察性质

可以递归的就递归处理子问题

Luogu3521 [POI2011]ROT-Tree Rotations

标签:交换   sdi   class   name   ==   line   c++   线段   dfs   

原文地址:https://www.cnblogs.com/yspm/p/13291332.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!