【BZOJ3600】没有人的算术(替罪羊树+线段树)
大致题意: 定义任意数对\(>0\),数对之间比大小先比第一位、后比第二位,一开始数列全为\(0\),要求你支持\(a_k=(a_x,a_y)\)和询问区间最大值所在位置两种操作。
化数对为实数
直接记录数对显然是不现实,也不可能的。
考虑到若数对\((a,b)<(c,d),(c,d)<(e,f)\),则\((a,b)\)必然小于\((e,f)\),即数对之间的比大小具有传递性。
那么我们可以考虑把每个数对按其大小对应成一个实数,而实数之间的比大小就非常方便了,直接用线段树维护就可以处理询问了。
也就是说,我们只要知道如何化数对为实数,就可以解决整道题了。
替罪羊树
考虑到要把每个数对按大小对应成一个数,可以用平衡树。
具体地,就是对于每个点表示一个数对,并确定一个值域区间\([L,R]\),设\(MID=(L+R)/2\),则\(MID\)就是这个点代表的数对所对应的数,而这个点左儿子的值域区间就是\([L,MID]\),右儿子的值域区间就是\([MID,R]\)。
特殊地,根节点的值域区间为\([0,10^9]\)(其实直接\([0,1]\)也问题不大,注意要开\(double\))。
但是要注意,如果选取\(Treap,Splay\)等会旋转的平衡树,我们所维护的值域区间就会乱套,因此只能采取替罪羊树,而它在重构时可以暴力重新赋值。
(关于替罪羊树,可参考我的这篇博客)
注意到上面说到的重新赋值,也就是说,一个点对它所对应的实数可能是会发生变化的。
因此,在数对及线段树中,我们应该记录的是这个数对在平衡树中对应的节点编号,而非其具体值,在比大小时则可以通过调用得到其具体值进行比较(我一开始就因为这个调了很久)。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define M 500000
#define DB long double
#define RD Reg DB
#define CD Con DB&
using namespace std;
int n,a[N+5];DB p[M+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		I void readc(char& x) {W(isspace(x=tc()));}
		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
		Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
struct data
{
	int x,y;I data(CI a=0,CI b=0):x(a),y(b){}
	I bool operator < (Con data& o) Con {return p[x]!=p[o.x]?p[x]<p[o.x]:p[y]<p[o.y];}
	I bool operator == (Con data& o) Con {return x==o.x&&y==o.y;}
};
class ScapegoatTree//替罪羊树
{
	private:
		#define alpha 0.75
		#define PU(x) (O[x].Sz=O[O[x].S[0]].Sz+O[O[x].S[1]].Sz+1)
		#define Balance(x) (alpha*O[x].Sz>1.0*max(O[O[x].S[0]].Sz,O[O[x].S[1]].Sz))
		#define ReBuild(x,L,R) (cnt=0,Tr(x),SetUp(x,1,cnt,L,R))
		int rt,tot,cnt,cur[M+5];
		struct node {int Sz,S[2];data V;}O[M+5];
		I int ins(int& rt,CD L,CD R,Con data& v)//插入一个新数对,返回节点编号
		{
			if(!rt) return O[rt=++tot].V=v,p[rt]=(L+R)/2,O[rt].Sz=1,rt;if(O[rt].V==v) return rt;
			RD MID=(L+R)/2;RI t;return t=v<O[rt].V?ins(O[rt].S[0],L,MID,v):ins(O[rt].S[1],MID,R,v),PU(rt),t;
		}
		I void chk(int& rt,CD L,CD R,Con data& v)//检验是否平衡
		{
			if(!rt) return;if(!Balance(rt)) return ReBuild(rt,L,R);if(O[rt].V==v) return;
			RD MID=(L+R)/2;v<O[rt].V?chk(O[rt].S[0],L,MID,v):chk(O[rt].S[1],MID,R,v);
		}
		I void Tr(CI x) {x&&(Tr(O[x].S[0]),cur[++cnt]=x,Tr(O[x].S[1]),0);}//中序遍历,存下节点
		I void SetUp(int& rt,CI l,CI r,CD L,CD R)//重构
		{
			RI mid=l+r>>1;RD MID=(L+R)/2;p[rt=cur[mid]]=MID,//重新赋值
			l<mid?(SetUp(O[rt].S[0],l,mid-1,L,MID),0):(O[rt].S[0]=0),//处理左儿子
			r>mid?(SetUp(O[rt].S[1],mid+1,r,MID,R),0):(O[rt].S[1]=0),PU(rt);//处理右儿子
		}
	public:
		I int Ins(CI x,CI y) {RI t;data w(x,y);return t=ins(rt,0,1e9,w),chk(rt,0,1e9,w),t;}
		#undef PU
}T;
class SegmentTree//线段树
{
	private:
		#define P CI l=1,CI r=n,CI rt=1
		#define L l,mid,rt<<1
		#define R mid+1,r,rt<<1|1
		#define mp make_pair
		#define fir first
		#define sec second
		#define Max(X,Y) (p[a[X]]>=p[a[Y]]?X:Y)
		#define PU(x) (Mx[x]=Max(Mx[x<<1],Mx[x<<1|1]))
		int Mx[N<<2];
	public:
		I void Build(P)//建树
		{
			if(l==r) return (void)(Mx[rt]=l);RI mid=l+r>>1;Build(L),Build(R),PU(rt);
		}
		I void Upt(CI x,P)//修改,实际上只是刷新一下这个点到根路径上的信息
		{
			if(l==r) return;RI mid=l+r>>1;x<=mid?Upt(x,L):Upt(x,R),PU(rt);
		}
		I int Qry(CI tl,CI tr,P)//询问
		{
			if(tl<=l&&r<=tr) return Mx[rt];RI mid=l+r>>1;RI t,res=0;
			tl<=mid&&(t=Qry(tl,tr,L),res?(res=Max(res,t)):(res=t)),
			tr>mid&&(t=Qry(tl,tr,R),res?(res=Max(res,t)):(res=t));return res;
		}
}S;
int main()
{
	RI Qt,i,l,r,k;char op;F.read(n),F.read(Qt),S.Build();
	for(T.Ins(0,0),i=1;i<=n;++i) a[i]=1;//初始化
	W(Qt--) F.readc(op),F.read(l),F.read(r),//读入
		op=='C'?F.read(k),a[k]=T.Ins(a[l],a[r]),S.Upt(k):F.writeln(S.Qry(l,r));//处理
	return F.clear(),0;
}
												
											【BZOJ3600】没有人的算术(替罪羊树+线段树)的更多相关文章
- 「BZOJ3065」带插入区间第K小值 替罪羊树×线段树
		
题目描述 从前有\(n\)只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力\(a_i\).跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间\(k\)小值.他 ...
 - 浅谈树套树(线段树套平衡树)&学习笔记
		
0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...
 - 「BZOJ3600」没有人的算术 替罪羊树+线段树
		
题目描述 过长--不想发图也不想发文字,所以就发链接吧-- 没有人的算术 题解 \(orz\)神题一枚 我们考虑如果插入的数不是数对,而是普通的数,这就是一道傻题了--直接线段树一顿乱上就可以了. 于 ...
 - 【BZOJ3600】没有人的算术 - 替罪羊树+线段树
		
题意: 题解: Orz vfleaking……真·神题 做法大概是先把题意中定义的“数”都赋一个实数权值,用平衡树来维护整个从大到小排序过的序列,再用线段树查询最值: 这样做为什么是对的?考虑插入一个 ...
 - bzoj 3600 没有人的算术 - 替罪羊树 - 线段树
		
题目都是图片,就不给了,就给链接好了 由于bzoj比较慢,就先给[vjudge传送门] 有兴趣的可以去逛bzoj[bzoj传送门] 题目大意 有n个数a[1],a[2],...,a[n],它们开始都是 ...
 - 【题解】BZOJ 3600: 没有人的算术——替罪羊树、线段树
		
题目传送门 题意 具体的自己去上面看吧...反正不是权限题. 简单来说,就是定义了一类新的数,每个数是0或者为 \((x_L, x_R)\) ,同时定义比较大小的方式为:非零数大于零,否则按字典序比较 ...
 - [BZOJ3600] 没有人的算术 [重量平衡树+权值线段树]
		
题面 传送门 思路 这道题目是陈立杰论文<重量平衡树和后缀平衡树在信息学奥赛中的应用 >中关于重量平衡树维护序列排名算法的一个应用 具体方法为:令根节点保存一个实数区间$[0,1]$ 若当 ...
 - bzoj3600: 没有人的算术
		
题意:太难说了..手动去看吧反正不是权限题. 膜拜VFK大爷的神题! 其实一开始思路挺清楚的,如果我们能做到用一个实数去代表"数",这就是裸的动态区间最值查询. 关键是怎么用实数去 ...
 - Codeforces 1045A Last chance 网络流,线段树,线段树优化建图
		
原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045A.html 题目传送们 - CF1045A 题意 你有 $n$ 个炮,有 $m$ 个敌人,敌人排成一 ...
 
随机推荐
- 第05组 Beta冲刺(2/4)
			
第05组 Beta冲刺(2/4) 队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了哪 ...
 - 图书分享 -《Natural Language Processing with Python》
			
-<Natural Language Processing with Python> 链接:https://pan.baidu.com/s/1_oalRiUEw6bXbm2dy5q_0Q ...
 - 80%应聘者都不及格的JS面试题
			
共 5024 字,读完需 6 分钟,速读需 2 分钟,本文首发于知乎专栏前端周刊.写在前面,笔者在做面试官这 2 年多的时间内,面试了数百个前端工程师,惊讶的发现,超过 80% 的候选人对下面这道题的 ...
 - springboot整合shiro进行权限管理
			
背景:springboot2.1,shiro1.4:由于目前的小项目没做登录,但是客户又需要加上权限,因此楼主就想到了shiro(这是单独的项目,需要集成后台管理系统) shiro简介 Apache ...
 - 新手入门:python的pip安装(二)
			
pip的安装以及使用pip安装包 —–安装python的时候勾选了下载pip,不知道为什么没下载.然后就偷懒想着需要哪个包再单独去下载就好了,然后!!!每个包都会出点小问题,导致我这个初学者有三天不想 ...
 - Java13 闪亮来袭,你是否还停留在 Java8
			
近期 Java 界好消息频传.先是 Java 13 发布,接着 Eclipse 也发布了新版本表示支持新版本的 Java 特性. 本文介绍了 Java 13 的新特性并展示了相关的示例. 2019 年 ...
 - pytest框架之rerunfailures失败重运行机制
			
web自动化测试中,稳定性在整个测试运行中都至关重要,但不能保证测试脚本或者测试环境一直都能够稳定,它牵扯到诸多因素,在这里就不赘述,pytest框架相较于unittest的一大优势就在于拥有用例失败 ...
 - 【CF704D】Captain America(上下界网络流)
			
[CF704D]Captain America(上下界网络流) 题面 CF 洛谷 题解 如果没有限制,似乎就不用做了...因为我们只需要贪心的选择代价较小的颜色就行了. 那么我们不妨假设染红色的代价较 ...
 - 利用zabbix监控ogg进程(Windows平台下)
			
本文给大家介绍如何监控windows平台下的ogg程序.(注:所有操作都在administrator用户下面进行操作) 监控linux平台下的ogg程序请看:https://www.cnblogs.c ...
 - Redisson实现分布式锁(3)—项目落地实现
			
Redisson实现分布式锁(3)-项目落地实现 有关Redisson实现分布式锁前面写了两篇博客作为该项目落地的铺垫. 1.Redisson实现分布式锁(1)---原理 2.Redisson实现分布 ...