bzoj 3600 没有人的算术——二叉查找树动态标号
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3600
已知 l 和 r 的排名,想快速知道 k 的排名。那么建一个 BIT ,用已知的排名做比较,走到一个位置,就知道自己的排名了。
但这样会让很多点的排名改变。如果用实数表示标号就可以方便地生成一个 “两个排名之间的排名” 而不影响其他点。
BIT 的每个节点代表一个曾经出现过的序列里的点,有自己的实数标号和 ( l , r ) 的组成。
如果把实数标号不是记在 BIT 节点上而是记在序列上,即 v[ i ] 表示序列第 i 个位置的标号,那么修改 k 位置的话,其他曾经调用 k 而组成的点也会收到影响。
所以实数标号记在 BIT 节点上,序列记一个 dy[ ] 表示它对应 BIT 哪个点。序列一个位置的 ( l , r ) 记录成 BIT 上对应的点即可。
用替罪羊树实现平衡。那么在重构的时候要注意,因为 dy[ ] 不会改变,所以 BIT 上点标之间的大小关系也不应改变。只要在回收的时候不是回收 Node 而是回收 int 即可(int 是那个 Node 的角标)。
最开始的时候只有一个 0 。那么 BIT 里唯一的节点表示 “只有一个 0 ” ,其 l 就是自己, r 是 0 (BIT 节点从1标号)。v[ 1 ] 会是 0.5 (如果标号总范围是 ( 0 , 1 ) 的话), v[ 0 ] 会是 0 ,这样就表示了 “没有” 是最小的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define db double
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=1e5+,M=5e5+;
const db sl=0.75;
int n,rt,tot,c0[M],c1[M],siz[M],dy[N]; db v[M];
int Ls[N<<],Rs[N<<],mx[N<<];
int rcr,rfa,sta[M],top; bool rfx; db rL,rR;
struct Node{
int l,r;
Node(int l=,int r=):l(l),r(r) {}
bool operator< (const Node &b)const
{ return v[l]==v[b.l]?v[r]<v[b.r]:v[l]<v[b.l];}
bool operator== (const Node &b)const
{ return v[l]==v[b.l]&&v[r]==v[b.r];}
}a[M];
int Mx(int u,int v){return u>v?u:v;}
Node Mx(Node u,Node v){return u<v?v:u;}
void build(int l,int r,int cr)
{
mx[cr]=l; if(l==r)return;
int mid=l+r>>;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+,r,rs);
}
void mdfy(int l,int r,int cr,int p)
{
if(l==r)return; int mid=l+r>>;
if(p<=mid)mdfy(l,mid,ls,p);
else mdfy(mid+,r,rs,p);
if(a[dy[mx[ls]]]<a[dy[mx[rs]]])mx[cr]=mx[rs];
else mx[cr]=mx[ls];
}
int qry(int l,int r,int cr,int L,int R)
{
if(l>=L&&r<=R)return mx[cr];
int mid=l+r>>;
if(R<=mid)return qry(l,mid,ls,L,R);
if(mid<L)return qry(mid+,r,rs,L,R);
int u=qry(l,mid,ls,L,R), v=qry(mid+,r,rs,L,R);
if(a[dy[u]]<a[dy[v]])return v;
else return u;
}
void chk(int cr,db L,db Md,db R)
{
if(Mx(siz[c0[cr]],siz[c1[cr]])>=siz[cr]*sl)rcr=cr;
if(rcr==c0[cr])
{ rfa=cr; rfx=; rL=L; rR=Md;}
if(rcr==c1[cr])
{ rfa=cr; rfx=; rL=Md; rR=R;}
}
int ins(int &cr,Node k,db L,db R)
{
db Md=(L+R)/;
if(!cr)
{
cr=++tot; a[cr]=k;
v[cr]=Md;siz[cr]=;return cr;
}
if(k==a[cr])return cr;
int ret=; siz[cr]++;
if(k<a[cr])ret=ins(c0[cr],k,L,Md);
else ret=ins(c1[cr],k,Md,R);
chk(cr,L,Md,R); return ret;
}
void del_dfs(int cr)//sorted!!
{
if(c0[cr])del_dfs(c0[cr]);
sta[++top]=cr;
if(c1[cr])del_dfs(c1[cr]);
}
void bld(int l,int r,int &cr,db L,db R)
{
db Md=(L+R)/; int mid=l+r>>;
cr=sta[mid];
c0[cr]=c1[cr]=; siz[cr]=; v[cr]=Md;
if(l<mid)bld(l,mid-,c0[cr],L,Md);
if(mid<r)bld(mid+,r,c1[cr],Md,R);
siz[cr]=siz[c0[cr]]+siz[c1[cr]]+;
}
void rebld(int &cr,db L,db R)
{
top=; del_dfs(cr); bld(,top,cr,L,R);
}
int main()
{
n=rdn();int m=rdn(); char ch[];
tot=;build(,n,);
tot=; ins(rt,Node(,),,);//v[1]=0.5//v[0]=0 is min
for(int i=;i<=n;i++)dy[i]=;
for(int i=,l,r,k;i<=m;i++)
{
scanf("%s",ch); l=rdn();r=rdn();
if(ch[]=='C')
{
k=rdn();
dy[k]=ins(rt,Node(dy[l],dy[r]),,);
Node tp=a[dy[k]];
mdfy(,n,,k);
if(rcr)
{
if(rcr==rt)rebld(rt,,);
else if(!rfx)rebld(c0[rfa],rL,rR);
else rebld(c1[rfa],rL,rR);
rcr=;
}
}
else printf("%d\n",qry(,n,,l,r));
}
return ;
}
bzoj 3600 没有人的算术——二叉查找树动态标号的更多相关文章
- bzoj 3600 没有人的算术 - 替罪羊树 - 线段树
题目都是图片,就不给了,就给链接好了 由于bzoj比较慢,就先给[vjudge传送门] 有兴趣的可以去逛bzoj[bzoj传送门] 题目大意 有n个数a[1],a[2],...,a[n],它们开始都是 ...
- bzoj 3600: 没有人的算术
Description Solution 我们可以给每一个数钦定一个权值 , 这样就可以 \(O(1)\) 比较大小了. 考虑怎么确定权值: 用平衡树来维护 , 我们假设根节点管辖 \([1,2^{6 ...
- 【题解】BZOJ 3600: 没有人的算术——替罪羊树、线段树
题目传送门 题意 具体的自己去上面看吧...反正不是权限题. 简单来说,就是定义了一类新的数,每个数是0或者为 \((x_L, x_R)\) ,同时定义比较大小的方式为:非零数大于零,否则按字典序比较 ...
- 「BZOJ3600」没有人的算术 替罪羊树+线段树
题目描述 过长--不想发图也不想发文字,所以就发链接吧-- 没有人的算术 题解 \(orz\)神题一枚 我们考虑如果插入的数不是数对,而是普通的数,这就是一道傻题了--直接线段树一顿乱上就可以了. 于 ...
- bzoj 2594: [Wc2006]水管局长数据加强版 动态树
2594: [Wc2006]水管局长数据加强版 Time Limit: 25 Sec Memory Limit: 128 MBSubmit: 934 Solved: 291[Submit][Sta ...
- BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树
题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...
- bzoj3600: 没有人的算术
题意:太难说了..手动去看吧反正不是权限题. 膜拜VFK大爷的神题! 其实一开始思路挺清楚的,如果我们能做到用一个实数去代表"数",这就是裸的动态区间最值查询. 关键是怎么用实数去 ...
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
这种动态点分治嘛,GDKOI时听打到了,也有同学讲到了,所以印象比较深刻也就想出来了,然后就在实现方面卡了好久= = 不得不说CLJ说得真的太简单了,实现方面根本没提. 首先我们可以先用树分治构建出这 ...
- BZOJ 2055: 80人环游世界 [上下界费用流]
2055: 80人环游世界 题意:n个点带权图,选出m条路径,每个点经过val[i]次,求最小花费 建图比较简单 s拆点限制流量m 一个点拆成两个,限制流量val[i],需要用上下界 图中有边的连边, ...
随机推荐
- 初识linux------用户和用户组
事先说明 本Linux的版本为Ubuntu. 为避免一些初学者由于权限问题特此事先说明,在非root权限下时,所有的代码加sudo:如下 (1)不在root权限 sudo useradd -m 用户名 ...
- mkdir 获得新建文件权限
使用mkdir创建文件夹时,发现这个函数有两个参数,第二个参数是为新创建的文件夹指定权限. 但是如果直接用mkdir('文件地址', 0777);时 发现新文件夹的权限并不是777,一般情况下会是02 ...
- C# 曲线控件 曲线绘制 实时曲线 多曲线控件 开发
Prepare 本文将使用一个NuGet公开的组件来实现曲线的显示,包含了多种显示的模式和配置来满足各种不同的应用场景,方便大家进行快速的开发系统. 在Visual Studio 中的NuGet管理器 ...
- Linux批量解压文件
最近下载了Imagenet2012的数据文件,训练数据下有很多tar文件,这些tar文件都在一个目录内,所以想批量解压到该目录下每个单独的文件夹内 批量解压的步骤是, 1.列出所有的以tar为后缀的文 ...
- How did I Install DCGAN
https://github.com/carpedm20/DCGAN-tensorflow how to install pillow(python image library) http://www ...
- 论container的前世今生
why Normally, thin-client multitiered applications are hard to write because they involve many lines ...
- ZOJ4067 Books(贪心)
题目链接:传送门 题目大意: DG在书店买书,从左到右第i本书价格为ai.DG从左走到右,能买就买.如果已知DG买了m本书,问他原本最多有多少钱.若无上限,输出“Richman”,若不可能买这么多书, ...
- java-Random类
1.Random类的概述和方法使用 * A:Random类的概述 * 此类用于产生随机数 * 如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数 ...
- php基础-1
php规范 php文件以<?php开头,以?>结尾. php可以和html代码混写,若当前文件为纯php代码 ,则不用写php结尾 php的一行代码以";"(分号)结尾 ...
- Centos6.8 搭建Tomcat服务器
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,是一个可以提供web服务同时也支持Servlet的JSP服务器. ...