题面

传送门

思路

这道题目是陈立杰论文《重量平衡树和后缀平衡树在信息学奥赛中的应用 》中关于重量平衡树维护序列排名算法的一个应用

具体方法为:令根节点保存一个实数区间$[0,1]$

若当前节点是$[l,r]$,则左儿子是$[l,mid]$,右儿子是$[mid,r]$

令$f[x]=(l[x]+r[x])*0.5$,则$f$比较大小则等价于序列中的元素比较大小

此时,用重量平衡树来实现这一过程,可以做到均摊$O(\log n)$修改,$O(1)$查询两个点之间的大小关系

本题中,考虑使用一棵平衡树来维护所有位置的排名,再用一棵权值线段树统计答案,权值线段树中保存对应区间的最大的点的下标,利用上面求出的$f$值来比大小

平衡树选取替罪羊树,实现时我们维护一个$node$类,保存它的左半和右半部分(本题中数是由两个部分组成的,也就是括号序列)在平衡树中的排名

插入时按照题目给定的方式比较即可,不需要删除

Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cassert>
#include<vector>
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
//scapegoat
double f[600010];int root,unb;
struct node{
int l,r;
friend bool operator >(node x,node y){
if(f[x.l]>f[y.l]) return 1;
if(f[x.l]==f[y.l]&&f[x.r]>f[y.r]) return 1;
return 0;
}
friend bool operator ==(node x,node y){
return (f[x.l]==f[y.l])&&(f[x.r]==f[y.r]);
}
};
namespace scp{
node a[600010];
int siz[600010],key[600010][2],ch[600010][2],pos[600010],cntn;
void update(int x){
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
vector<int>str;
void dfs(int u){
if(!u) return;
dfs(ch[u][0]);
str.push_back(u);
dfs(ch[u][1]);
}
void build(int &cur,int l,int r,double ql,double qr){
if(l>r){cur=0;return;}
int mid=(l+r)>>1;double md=(ql+qr)*0.5;
cur=str[mid];
f[cur]=md;
build(ch[cur][0],l,mid-1,ql,md);
build(ch[cur][1],mid+1,r,md,qr);
update(cur);
}
void rebuild(int &u,double l,double r){
str.clear();
dfs(u);
build(u,0,str.size()-1,l,r);
}
double alpha=0.75;int cho;
int insert(int &cur,node val,double ql,double qr){
double mid=(ql+qr)*0.5;
if(!cur){
cur=++cntn;f[cur]=mid;a[cur]=val;siz[cur]=1;
return cur;
}
int p;
if(val==a[cur]){p=cur;return p;}
else{
siz[cur]++;
if(val>a[cur]) p=insert(ch[cur][1],val,mid,qr);
else p=insert(ch[cur][0],val,ql,mid);
}
if((double)(siz[cur]*0.75)>(double)(max(siz[ch[cur][0]],siz[ch[cur][1]]))){
if(unb){
if(ch[cur][0]==unb) rebuild(ch[cur][0],ql,mid);
else rebuild(ch[cur][1],mid,qr);
unb=0;
}
}
else unb=cur;
return p;
}
}
int maxn[1000010],pos[1000010];
void change(int l,int r,int p,int cur){
int mid=(l+r)>>1;
if(l==r){maxn[p]=l;return;}
if(mid>=cur) change(l,mid,p<<1,cur);
else change(mid+1,r,p<<1|1,cur);
if(f[pos[maxn[p<<1]]]>=f[pos[maxn[p<<1|1]]]) maxn[p]=maxn[p<<1];
else maxn[p]=maxn[p<<1|1];
}
int query(int l,int r,int ql,int qr,int num){
if(l>=ql&&r<=qr) return maxn[num];
int mid=(l+r)>>1,re,re1;
if(mid>=qr) return query(l,mid,ql,qr,num<<1);
else if(mid<ql) return query(mid+1,r,ql,qr,num<<1|1);
else{
re=query(l,mid,ql,mid,num<<1);
re1=query(mid+1,r,mid+1,qr,num<<1|1);
if(f[pos[re]]>=f[pos[re1]]) return re;
else return re1;
}
}
int n,Q;
int main(){
n=read();Q=read();int i,t1,t2,t3;char s[10];
scp::insert(root,(node){0,0},0,1);f[0]=-1;
for(i=1;i<=n;i++) pos[i]=1;
for(i=1;i<=n;i++) change(1,n,1,i);
while(Q--){
scanf("%s",s);
t1=read();t2=read();
if(s[0]=='C'){
t3=read();unb=0;
pos[t3]=scp::insert(root,(node){pos[t1],pos[t2]},0,1);
if(unb) scp::rebuild(root,0,1);
change(1,n,1,t3);
}
else printf("%d\n",query(1,n,t1,t2,1));
}
}

[BZOJ3600] 没有人的算术 [重量平衡树+权值线段树]的更多相关文章

  1. cogs 1829. [Tyvj 1728]普通平衡树 权值线段树

    1829. [Tyvj 1728]普通平衡树 ★★★   输入文件:phs.in   输出文件:phs.out   简单对比时间限制:1 s   内存限制:1000 MB [题目描述] 您需要写一种数 ...

  2. [BZOJ3196] 二逼平衡树 [权值线段树套位置平衡树]

    题面 洛咕题面 思路 没错我就是要不走寻常路! 看看那些外层位置数据结构,必须二分的,$O(n\log^3 n)$的做法吧! 看看那些cdq分治/树状数组套线段树的,空间$O(n\log^2 n)$挤 ...

  3. BZOJ_3224 Tyvj 1728 普通平衡树 【离散化+权值线段树】

    一 题面 Tyvj 1728 普通平衡树 二 分析 比较明显是可以用平衡二叉搜索树(splay)做的. 用权值线段树做,前提就是要先离散化,因为权值线段树维护的值域信息. 板子. 三 AC代码 #in ...

  4. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

  5. luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)

    带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...

  6. 【bzoj4399】魔法少女LJJ 并查集+权值线段树合并

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味: ...

  7. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  8. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  9. BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树

    BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资. ...

随机推荐

  1. [优化]Steamroller-freecodecamp算法题目

    晚上在medium看到一篇关于找工作的文章,里面提到一个面试题目--flattening an array(扁平化数组).这我好像在哪看过!应该是freecodecamp里的算法某一题.翻了下博客记录 ...

  2. Java分享笔记:使用entrySet方法获取Map集合中的元素

    /*--------------------------------- 使用entrySet方法取出Map集合中的元素: ....该方法是将Map集合中key与value的关系存入到了Set集合中,这 ...

  3. mybatis两级缓存原理剖析

    https://blog.csdn.net/zhurhyme/article/details/81064108 对于mybatis的缓存认识一直有一个误区,所以今天写一篇文章帮自己订正一下.mybat ...

  4. 自定义扩展Compare比较方法

    public static int Compare<T, V>(this T x, T y, Func<T, V> func) { return Comparer<V&g ...

  5. 记一次samba排错 Failed to start Samba SMB Daemon.

       记录一次服务出错排错的过程,很多新手出了点错不百度直接巴拉巴拉的问,一般老手根据经验可以给出一点建议,但是由于个体环境的差异并不适用,反而埋怨起来.这种真的无F**K可说,所以要培养自己的排错能 ...

  6. Java高并发之同步异步

    1.概念理解: 2.同步的解决方案: 1).基于代码 synchronized 关键字 修饰普通方法:作用于当前实例加锁,进入同步代码前要获得当前实例的锁. 修饰静态方法:作用于当前类对象加锁,进入同 ...

  7. php扩展开发-INI配置

    php.ini文件是用来保存各项扩展配置的文件,每个扩展都或多或少需要有一个定制化的配置,ini文件是一个很好的保存配置的方式,我们来看下怎么在自己的扩展里,使用到ini的配置功能 //创建ini的配 ...

  8. Requests库:python实现的简单易用的http库

    1.get请求: get(url, params, headers) 2.json 解析 3.content 获取二进制内容 4.headers 添加 5.post请求:post(url,data,h ...

  9. Highest Tower 18中南多校第一场H题

    一.题意 给出N个方块,要求给出一个方案,使得1. 所有方块都被使用到(题目数据保证这点) 2.所有方块垒成一个塔,且上面的方块宽度小于下面的方块 3.每个方块只能用一次,可以横着或者竖着. n范围5 ...

  10. Flask错误收集 【转】

    感谢大佬 ---> 原文链接 一.pydev debugger: process XXXXX is connecting 这个错误网上找了很多资料都无法解决,尝试过多种方法后,对我来说,下面这个 ...