bzoj3600: 没有人的算术
题意:太难说了。。手动去看吧反正不是权限题。
膜拜VFK大爷的神题!
其实一开始思路挺清楚的,如果我们能做到用一个实数去代表“数”,这就是裸的动态区间最值查询。
关键是怎么用实数去表示。如果我们单纯的把两个数进行O(1)运算去得到一个实数,这样很轻松就会被卡掉,因为无论是longlong还是double都是有限度的。怎么做呢?
这里有一个技巧:我们维护一个重量平衡树,每个节点管辖一个区间,这个区间的中位数为这个点的权值,而它的左儿子管辖左半边,右儿子管辖右半边。
问题来了,这不是差不多吗?并不是这样。因为我们会重构,树高有保证,所以我们肯定能表示出每一个数,而且还是绰绰有余。
重量平衡树可以用不旋转的treap或替罪羊树。
(吐槽一句,第一次写替罪羊树,真的好TM难写啊还套了个线段树而且我常数大的飞起,写了一整天)
#include<bits/stdc++.h>
using namespace std;
#define N 500005
#define LL long long
inline LL read(){
LL x=,f=; char a=getchar();
while(a<'' || a>'') {if(a=='-') f=-; a=getchar();}
while(a>='' && a<='') x=x*+a-'',a=getchar();
return x*f;
}
int n,m; char st[];
LL MX;
#define SGT Scapegoat_Tree
#define ST Segment_Tree namespace Scapegoat_Tree{
#define eps 1e-12
const double alpha=0.75;
int ltst,wh,size=,tmp[N],root=,anew;
struct sgt{
LL l,r,mid; int fir,sec;
int son[],sz;
}tr[N];
inline int dcmp(int x,int y){
if(fabs((double)tr[x].sz*alpha-(double)tr[y].sz)<eps) return ;
else return (double)tr[x].sz*alpha>(double)tr[y].sz?:-;
}
inline void update(int x){
tr[x].sz=tr[tr[x].son[]].sz+tr[tr[x].son[]].sz+;
}
inline bool balance(int x){
return dcmp(x,tr[x].son[])>= && dcmp(x,tr[x].son[])>=;
}
void travel(int x){
if(!x) return;
travel(tr[x].son[]);
tmp[++tmp[]]=x;
travel(tr[x].son[]);
}
void rebuild(int &x,int l,int r,LL L,LL R){
if(l>r) {x=; return;}
int mid=(l+r)>>;
LL M=(L+R)/;
x=tmp[mid]; tr[x].l=L; tr[x].r=R; tr[x].mid=M;
if(l==r) {tr[x].sz=; tr[x].son[]=; tr[x].son[]=; return;}
rebuild(tr[x].son[],l,mid-,L,M); rebuild(tr[x].son[],mid+,r,M,R);
update(x);
}
void insert(int& x,LL L,LL R,int fir,int sec){
if(!x) {x=++size; anew=x;tr[x]=(sgt){L,R,(L+R)/,fir,sec,,,}; return;}
if(tr[tr[x].fir].mid==tr[fir].mid && tr[tr[x].sec].mid==tr[sec].mid) {anew=x; return;}
else if(tr[tr[x].fir].mid==tr[fir].mid){
if(tr[tr[x].sec].mid>tr[sec].mid) insert(tr[x].son[],tr[x].l,tr[x].mid,fir,sec);
else insert(tr[x].son[],tr[x].mid,tr[x].r,fir,sec);
}
else{
if(tr[tr[x].fir].mid>tr[fir].mid) insert(tr[x].son[],tr[x].l,tr[x].mid,fir,sec);
else insert(tr[x].son[],tr[x].mid,tr[x].r,fir,sec);
}
update(x);
if(tr[x].son[] && !balance(tr[x].son[])) ltst=x,wh=;
else if(tr[x].son[] && !balance(tr[x].son[])) ltst=x,wh=;
if(x==root && !balance(x)) tmp[]=,travel(root),rebuild(root,,tmp[],,MX);
}
}
namespace Segment_Tree{
int a[N];
struct seg{
int l,r,son[],mx_pos,num;
}tr[N];
inline void update(int x){
if(SGT::tr[tr[tr[tr[x].son[]].mx_pos].num].mid==SGT::tr[tr[tr[tr[x].son[]].mx_pos].num].mid){
int le=tr[tr[x].son[]].mx_pos,ri=tr[tr[x].son[]].mx_pos;
tr[x].mx_pos=tr[le].l<tr[ri].l?le:ri;
}
else if(SGT::tr[tr[tr[tr[x].son[]].mx_pos].num].mid>SGT::tr[tr[tr[tr[x].son[]].mx_pos].num].mid)
tr[x].mx_pos=tr[tr[x].son[]].mx_pos;
else tr[x].mx_pos=tr[tr[x].son[]].mx_pos;
}
void build(int x,int l,int r){
if(l==r) {tr[x]=(seg){l,r,,,x,};return;}
int mid=(l+r)>>; tr[x].l=l; tr[x].r=r;
tr[x].son[]=x<<; build(tr[x].son[],l,mid);
tr[x].son[]=x<<|; build(tr[x].son[],mid+,r);
update(x);
}
void modify(int x,int ai,int v){
int l=tr[x].l,r=tr[x].r;
if(l==r) {tr[x].num=v; return;}
int mid=(l+r)>>;
if(ai<=mid) modify(tr[x].son[],ai,v);
else modify(tr[x].son[],ai,v);
update(x);
}
int query(int x,int L,int R){
int l=tr[x].l,r=tr[x].r;
if(l==L && r==R) return tr[x].mx_pos;
int mid=(l+r)>>;
if(R<=mid) return query(tr[x].son[],L,R);
else if(mid<L) return query(tr[x].son[],L,R);
else{
int le=query(tr[x].son[],L,mid),ri=query(tr[x].son[],mid+,R);
if(SGT::tr[tr[le].num].mid==SGT::tr[tr[ri].num].mid) return tr[le].l<tr[ri].l?le:ri;
return SGT::tr[tr[le].num].mid>SGT::tr[tr[ri].num].mid?le:ri;
}
}
} int main(){
n=read(); m=read(); MX=;
for(int i=;i<=;i++) MX*=;
ST::build(,,n); SGT::tr[]=(SGT::sgt){,MX,(+MX)/,,,,,};
for(int i=;i<=n;i++) ST::a[i]=;
while(m--){
scanf("%s",st); int k,l=read(),r=read();
if(st[]=='C'){
k=read();
l=ST::a[l]; r=ST::a[r]; SGT::ltst=; SGT::insert(SGT::root,,MX,l,r);
if(SGT::ltst) {
SGT::tmp[]=; SGT::travel(SGT::tr[SGT::ltst].son[SGT::wh]);
LL L=SGT::tr[SGT::tr[SGT::ltst].son[SGT::wh]].l,R=SGT::tr[SGT::tr[SGT::ltst].son[SGT::wh]].r;
SGT::rebuild(SGT::tr[SGT::ltst].son[SGT::wh],,SGT::tmp[],L,R);
}
ST::modify(,k,SGT::anew),ST::a[k]=SGT::anew;
}else{
int ans=ST::query(,l,r);
ans=ST::tr[ans].l;
printf("%d\n",ans);
}
}
return ;
}
bzoj3600: 没有人的算术的更多相关文章
- [BZOJ3600] 没有人的算术 [重量平衡树+权值线段树]
题面 传送门 思路 这道题目是陈立杰论文<重量平衡树和后缀平衡树在信息学奥赛中的应用 >中关于重量平衡树维护序列排名算法的一个应用 具体方法为:令根节点保存一个实数区间$[0,1]$ 若当 ...
- 「BZOJ3600」没有人的算术 替罪羊树+线段树
题目描述 过长--不想发图也不想发文字,所以就发链接吧-- 没有人的算术 题解 \(orz\)神题一枚 我们考虑如果插入的数不是数对,而是普通的数,这就是一道傻题了--直接线段树一顿乱上就可以了. 于 ...
- BZOJ3600:没有人的算术
传送门 如果能给每个 \(pair\) 按照权值编号就好了 假设之前已经有了所有的权值的编号,现在考虑编号新的 \(pair\) 如果看过了陈立杰的论文的话,不难得到一个重量平衡树的做法 给树上每个子 ...
- 【BZOJ3600】没有人的算术 - 替罪羊树+线段树
题意: 题解: Orz vfleaking……真·神题 做法大概是先把题意中定义的“数”都赋一个实数权值,用平衡树来维护整个从大到小排序过的序列,再用线段树查询最值: 这样做为什么是对的?考虑插入一个 ...
- 【BZOJ3600】没有人的算术(替罪羊树+线段树)
点此看题面 大致题意: 定义任意数对\(>0\),数对之间比大小先比第一位.后比第二位,一开始数列全为\(0\),要求你支持\(a_k=(a_x,a_y)\)和询问区间最大值所在位置两种操作. ...
- bzoj 3600 没有人的算术——二叉查找树动态标号
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3600 已知 l 和 r 的排名,想快速知道 k 的排名.那么建一个 BIT ,用已知的排名做 ...
- 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)\) ,同时定义比较大小的方式为:非零数大于零,否则按字典序比较 ...
随机推荐
- Learning by doing
Learning by doing 绪论:读了娄老师的公众号中--<做中学(Learning By Doing)>这篇文章后,深有感触,我想到很多自己之前的事情,很多都是每每想的很好,总是 ...
- php封装微信SDK
<?phpclass JSSDK { private $appId = '你公众号的appid'; private $appSecret = '你公众号的appSecret'; public f ...
- Tomcat目录映射设置
方法一: \conf\server.xml <Host>内插入<Context path="虚拟目录" docBase="文件目录" /> ...
- jquery.validate使用 - 自定义错误信息
自定义错误消息的显示方式 默认情况下,验证提示信息用label元素来显示, 并且会添加css class, 通过css可以很方便设置出错控件以及错误信息的显示方式. /* 输入控件验证出错*/form ...
- OpenCV从入门到放弃系列之——图像的基本操作
读取.修改.保存图像 图像读取函数imread(); 图像颜色空间的转换cvtColor(); 图像保存至硬盘imwrite(); /********************************* ...
- 【所见即所得】textarea 精确限制字数、行数,中、英、全半角混检 。源码带注释
主要解决难点: 1 中文 全角2字符深深的恶意 2 多行输入textarea 手动,自动换行问题 3 获得每行内容 原创,转载请注明出处! <!DOCTYPE html PUBLIC " ...
- Python notes
1. range()函数的使用: a = range(n) # a = range(0,n) b = range(m,n) # b = range(m,n) alist = list(a) # ali ...
- 漂亮的Linux命令提示符
漂亮的Linux命令提示符 每天面对着白底黑字(黑底白字)的命令行是否枯燥泛味呢?生活应给是五彩缤纷的,何不为单调无味的生活增添一抹色彩? 下面一起体验一下Linux命令行提示符惊险的整容之旅 惊鸿一 ...
- log4j PatternLayout 输出解析
以下是PatternLayout.class源码的文档介绍: A flexible layout configurable with pattern string. This code is know ...
- angularJS 学习之路
AngularJS 通过 ng-directives 扩展了 HTML. ng-app 指令定义一个 AngularJS 应用程序.也就是angularjs作用的入口 作用在什么标签或者整个body ...