首页 > 其他分享 >【BZOJ2212】【POI2011】【XSY2014】Tree Rotation(线段树合并)

【BZOJ2212】【POI2011】【XSY2014】Tree Rotation(线段树合并)

时间:2022-10-28 18:46:59浏览次数:50  
标签:XSY2014 ch lc 权值 POI2011 Tree rc size 逆序

输入格式真的毒瘤

权值线段树合并。

我们先对每一个叶子建一棵权值线段树,并把它自己的权值插入到里面。

我们不妨设原树中当前节点为 \(u\),爸爸 \(fa\),左儿子 \(lc\),右儿子 \(rc\),那么显然这棵树中的逆序对分为 \(3\) 个部分:\(lc\) 里的逆序对,\(rc\) 里的逆序对和跨 \(lc\) 和 \(rc\) 的逆序对。

而我们现在已经把 \(lc\) 里的逆序对和 \(rc\) 里的逆序对算好了,现在需要求出跨 \(lc\) 和 \(rc\) 的逆序对,也就是合并 \(lc\) 和 \(rc\) 。然后我们发现,无论 \(lc\) 内的子树怎么换来换去,\(rc\)内的子树怎么换来换去,都是对跨 \(lc\) 和 \(rc\) 的逆序对个数没有影响的。

同理,无论我们交不交换 \(lc\) 和 \(rc\),对 \(fa\) 那一层的合并也是没有影响的。

所以对于跨 \(lc\) 和 \(rc\) 的逆序对,我们分交换 \(lc\)、\(rc\) 和不交换的情况算出两种情况的逆序对个数,再取较小值就好了。

我们遍历两棵权值线段树来暴力合并两棵权值线段树。

那么对于 \(lc\) 和 \(rc\) 权值线段树中同一位置的点 \(a\)、\(b\),若不交换 \(lc\) 和 \(rc\),显然 \(lc\) 中的点的编号(这里的编号是指前序遍历的先后顺序)肯定都在 \(rc\) 前,\(a\) 右儿子的权值必定大于 \(b\) 左儿子的权值,所以 \(size[ch[a][1]]*size[ch[b][0]]\) 就是这一位置的答案了。

同理,如果交换 \(lc\) 和 \(rc\),这一位置的答案就是 \(size[ch[a][0]]*size[ch[b][1]]\)。

最后合并完统计答案即可。

代码如下:

#include<bits/stdc++.h>

#define N 200010
#define int long long

using namespace std;

struct Tree
{
	int ch[2],size;
}t[N<<5];

int n,tot,ans,num1,num2;

int update(int l,int r,int val)
{
	int u=++tot;
	t[u].size=1;
	if(l==r) return u;
	int mid=(l+r)>>1;
	if(val<=mid) t[u].ch[0]=update(l,mid,val);
	else t[u].ch[1]=update(mid+1,r,val);
	return u;
}

int merge(int a,int b,int l,int r)//把b合并至a
{
	if(!a||!b) return a+b;
	if(l==r)
	{
		t[a].size+=t[b].size;
		return a;
	}
	num1+=t[t[a].ch[1]].size*t[t[b].ch[0]].size;//不交换的答案
	num2+=t[t[b].ch[1]].size*t[t[a].ch[0]].size;//交换后的答案
	int mid=(l+r)>>1;
	t[a].ch[0]=merge(t[a].ch[0],t[b].ch[0],l,mid);
	t[a].ch[1]=merge(t[a].ch[1],t[b].ch[1],mid+1,r);
	t[a].size+=t[b].size;
	return a;
}

int dfs()
{
	int u,val;
	scanf("%lld",&val);
	if(!val)
	{
		int lc=dfs(),rc=dfs();
		num1=num2=0;
		u=merge(lc,rc,1,n);
		ans+=min(num1,num2);//ans加上较小值
	}
	else u=update(1,n,val);
	return u;
}

signed main()
{
	scanf("%lld",&n);
	dfs();
	printf("%lld\n",ans);
	return 0;
}

标签:XSY2014,ch,lc,权值,POI2011,Tree,rc,size,逆序
From: https://www.cnblogs.com/ez-lcw/p/16837101.html

相关文章

  • 【AGC023F】01 on Tree(树上一类全序问题)
    显然如果没有树的限制,我们优先选\(0\),然后选\(1\)。如果有了树的限制,我们考虑下面这么一种贪心方法:假设当前能够选的点的集合为\(S\)(初始时\(S\)只包含根),然后选出\(......
  • Hutool工具-TreeUtil封装树形结构数据,你用过了吗
    在开发过程中,必定会遇到树形结构的数据,一般都是后端直接从库里查询出来然后自定义方法去封装成树形树形返回给前端。其实Hutool工具类也提供了这个方法,这种方式使用起来也......
  • GeckoFx (4)使用 treeview 展示 dom 数树
    GeckoFx(4)使用treeview展示dom数树使用DocumentCompleted事件,在页面加载完成后构建一个dom树使用treeview控件。treeHtml:treeview......
  • 树 Tree
    树的结构后继节点和该后继节点的父节点,(一个节点的后继节点是指,这个节点在中序遍历序列中的下一个节点,相应的,前驱节点是指这个节点在中序遍历序列中的上一个节点树的结......
  • The 2021 ICPC Asia Nanjing Regional Contest E.Paimon Segment Tree 区间合并线段树
    The2021ICPCAsiaNanjingRegionalContestE.PaimonSegmentTree区间合并线段树/维护矩阵乘法题目大意给定长度为的序列,要求支持区间加操作,同时对操作记录历史版本,查......
  • 3.CF343D Water Tree 树剖+线段树区间覆盖
    3.CF343DWaterTree树剖+线段树区间覆盖线段树维护树上覆盖问题,树剖序列化维护序列覆盖。洛谷传送门:​​CF343DWaterTree-洛谷|计算机科学教育新生态(luogu.com.c......
  • 9.CF490F Treeland Tour 线段树合并
    9.CF490FTreelandTour线段树合并给出一棵带点权树,求树上最长上升子序列的长度对每个点开两棵线段树,记录叶节点到当前节点的LIS和LDS,然后合并时取最大值即可洛谷传送门:​......
  • Nauuo and Binary Tree 题解
    linkSolution超级有意思的题目,可惜还是做不出来。/kk我们首先看出我们可以求出每一个点的深度。然后考虑深度从小到大考虑对于每一个点找出它的父亲。你发现如果求出两......
  • [repo] error.GitError: cannot initialize work tree && contains uncommitted chang
    备忘一下error.GitError:cannotinitializeworktree.repo/repo/repo--tracesync-cdfjuwan@juwan-n85-dls:/media/juwan/70970A1D041A95C2/rk3399_linux_relea......
  • mysqlb+tree结构
    怎样在MySQL表中存储树形结构数据很高兴为您解答。一般比较普遍的就是四种方法:(具体见SQLAnti-patterns这本书)AdjacencyList:每一条记录存parent_idPathEnumerations:每一......