【模板】二逼平衡树(树套树)

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

查询k在区间内的排名

查询区间内排名为k的值

修改某一位值上的数值

查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

注意上面两条要求和tyvj或者bzoj不一样,请注意

输入输出格式

输入格式:

第一行两个数 n,m 表示长度为n的有序序列和m个操作

第二行有n个数,表示有序序列

下面有m行,opt表示操作标号

若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名

若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数

若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k

若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱

若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

输出格式:

对于操作1,2,4,5各输出一行,表示查询结果

说明

时空限制:2s,1256M

\(n,m \leq 5\cdot {10}^4\)

保证有序序列所有值在任何时刻满足\([0, {10} ^8]\)

题目来源:bzoj3196 / Tyvj1730 二逼平衡树,在此鸣谢

此数据为洛谷原创。(特别提醒:此数据不保证操作4、5一定存在,故请务必考虑不存在的情况)


前几天写了个树状数组套平衡树,最后懒得调了

花了很久写+调弄了树状数组套可持久化线段树

发现有思想的是 在多个可持久化树上一起二分

很烦人的是查排名时的一些存在性问题

最关键的是权值线段树想离散开点还必须离线

代码也不好看,以后还会写的


Code

#include <cstdio>
#include <algorithm>
#define sf num[i].second.first
#define ss num[i].second.second
using namespace std;
const int N=300010;
const int inf=2147483647;
int sum[N*50],ls[N*50],rs[N*50],root[N],las[N],tot,n,m,is,n_,n0,dat[N<<1];
pair <int,pair<int,int> > num[N<<1];
struct node
{int opt,l,r,k;
}op[N];
void change(int &now,int l,int r,int pos,int delta)
{if(!now) now=++tot;sum[now]+=delta;if(l==r) return;int mid=l+r>>1;if(pos<=mid) change(ls[now],l,mid,pos,delta);else change(rs[now],mid+1,r,pos,delta);
}
int query(int now,int l,int r,int pos)//1-pos的值
{if(l==r)return is=sum[now],0;if(!now||!pos) return sum[now];int mid=l+r>>1;if(pos<=mid) return query(ls[now],l,mid,pos);else return sum[ls[now]]+query(rs[now],mid+1,r,pos);
}
void add(int x,int pos,int delta)
{while(x<=n_){change(root[x],1,n,pos,delta);x+=x&-x;}
}
int Rank(int l,int r,int pos)//查询l-r区间pos的排名
{if(!pos) return 0;int rk=0,cnt0=0;for(int i=l-1;i;i-=i&-i)is=0,rk-=query(root[i],1,n,pos),cnt0-=is;for(int i=r;i;i-=i&-i)is=0,rk+=query(root[i],1,n,pos),cnt0+=is;return rk+(cnt0>0);
}
int rl[N],rr[N];
int frank(int l,int r,int k)//l到r排名为k的数
{int ad,de;for(int i=l-1;i;i-=i&-i) rl[i]=root[i];for(int i=r;i;i-=i&-i) rr[i]=root[i];int L=1,R=n;while(L<R){ad=de=0;int Mid=L+R>>1;for(int i=l-1;i;i-=i&-i) de+=sum[ls[rl[i]]];for(int i=r;i;i-=i&-i) ad+=sum[ls[rr[i]]];if(ad-de>=k){R=Mid;for(int i=l-1;i;i-=i&-i) rl[i]=ls[rl[i]];for(int i=r;i;i-=i&-i) rr[i]=ls[rr[i]];}else{L=Mid+1;k-=ad-de;for(int i=l-1;i;i-=i&-i) rl[i]=rs[rl[i]];for(int i=r;i;i-=i&-i) rr[i]=rs[rr[i]];}}return dat[L];
}
void pre(int l,int r,int pos)
{int rk=Rank(l,r,pos-1);if(!rk) printf("%d\n",-inf);else printf("%d\n",frank(l,r,rk));
}
void suc(int l,int r,int pos)
{add(l,pos+1,1);int rk=Rank(l,r,pos+1);add(l,pos+1,-1);if(rk==r+2-l) printf("%d\n",inf);else printf("%d\n",frank(l,r,rk));
}
void init()
{scanf("%d%d",&n_,&m);for(int i=1;i<=n_;i++){scanf("%d",&num[i].first);num[i].second.first=i;}n0=n_;for(int i=1;i<=m;i++){scanf("%d",&op[i].opt);if(op[i].opt==3)scanf("%d%d",&op[i].l,&op[i].k);elsescanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);if(op[i].opt!=2){num[++n0].first=op[i].k;num[n0].second.first=i+n_;}}sort(num+1,num+1+n0);num[0].first=inf;for(int i=1;i<=n0;i++){if(num[i].first!=num[i-1].first) ++n;ss=n,dat[n]=num[i].first;}for(int i=1;i<=n0;i++){if(sf<=n_) las[sf]=ss,add(sf,ss,1);else op[sf-n_].k=ss;}
}
void work()
{for(int i=1;i<=m;i++){if(op[i].opt==1){add(op[i].l,op[i].k,1);printf("%d\n",Rank(op[i].l,op[i].r,op[i].k));add(op[i].l,op[i].k,-1);}else if(op[i].opt==2) printf("%d\n",frank(op[i].l,op[i].r,op[i].k));else if(op[i].opt==3){add(op[i].l,las[op[i].l],-1);las[op[i].l]=op[i].k;add(op[i].l,las[op[i].l],1);}else if(op[i].opt==4)pre(op[i].l,op[i].r,op[i].k);elsesuc(op[i].l,op[i].r,op[i].k);}
}
int main()
{init();work();return 0;
}

2018.8.1

转载于:https://www.cnblogs.com/butterflydew/p/9403390.html

洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)相关推荐

  1. 【洛谷3865】 【模板】ST表(猫树)

    传送门 洛谷 Solution 实测跑的比ST表快!!! 这个东西也是\(O(1)\)的,不会可以看我上一篇Blog 代码实现 代码戳这里 转载于:https://www.cnblogs.com/ml ...

  2. BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

    我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...

  3. 【BZOJ3196】【Tyvj1730】二逼平衡树,第一次的树套树(线段树+splay)

    传送门1 传送门2 写在前面:创造迄今最长的正常代码的记录 思路:个人感觉这个树套树就是对线段树的每个区间建一棵splay来维护,最初觉得这个方法会爆T爆M--(实际上真的可能会爆).对于5个操作,我 ...

  4. [luogu3380][bzoj3196]【模板】二逼平衡树【树套树】

    题目地址 [洛谷传送门] 题目大意 区间查询k的排名,查找k排名的数,单点修改,区间前驱,区间后继. 感想 真的第一次写树套树,整个人都不对了.重构代码2次,发现样例都过不了,splay直接爆炸,可能 ...

  5. P3380 【模板】二逼平衡树(树套树)

    传送门 查询 kkk 在区间内的排名 查询区间内排名为 kkk的值 修改某一位值上的数值 查询 kkk 在区间内的前驱(前驱定义为严格小于 xxx,且最大的数,若不存在输出 −2147483647-2 ...

  6. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 2271  Solved: 935 [Submit][St ...

  7. 洛谷P4630 [APIO2018] Duathlon 铁人两项 【圆方树】

    题目链接 洛谷P4630 题解 看了一下部分分,觉得树的部分很可做,就相当于求一个点对路径长之和的东西,考虑一下能不能转化到一般图来? 一般图要转为树,就使用圆方树呗 思考一下发现,两点之间经过的点双 ...

  8. 【Luogu】P3380树套树模板(线段树套Splay)

    题目链接 幸甚至哉,歌以咏志. 拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装B的时候才挂在嘴边的树套树. 每道模板都是链上的一颗珠子.把它们挨个串起来,就成为我成长的历程. ...

  9. Bzoj 3196 Tyvj 1730 二逼平衡树

    3196: Tyvj 1730 二逼平衡树 >原题链接< Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...

最新文章

  1. 查询表的列名,字符类型
  2. Java-Web Response响应和Request请求
  3. vue计算属性computed与监听属性watch的基本使用
  4. Android笔记之自定义Editext
  5. 基于sqlite数据库的C语言编程
  6. linux ubuntu php,linux ubuntu安装php运行环境
  7. java web典型模块大全_python+selenium基于po模式的web自动化测试框架
  8. 图论画图有力工具 csacadmy app Graph Editor
  9. 阶段3 1.Mybatis_03.自定义Mybatis框架_6.自定义Mybatis的编码-实现基于XML的查询所有操作...
  10. 计算机软考论文网络真题,软考历年真题在线测试系统测试与开发
  11. No filesystem could mount root, tried: ext3 ext2 ext4 vfat msdos
  12. CTF---图片隐写相关
  13. 深度学习-图神经网络总结
  14. Mysql切换用户,登录用户
  15. VC++ MFC实现的优秀的开源项目
  16. 2017年总结--心情篇
  17. 软路由自建iptv服务器,LEDE软路由 iPTV 实现任意端口看电视的方法
  18. 三项式与组合数(lucas板子)
  19. 离散数学·命题逻辑【范式、推理】
  20. 数学之美读书笔记第一章

热门文章

  1. openjudge 1.10.3 成绩排序
  2. 生活中有哪些实用的心理学知识?
  3. Java性能优化权威指南--笔记
  4. python人机对话性别年龄名字_人机交互程序 python实现人机对话
  5. 学生选课及学籍管理C++
  6. ORACLE - 求 某年 -某月/某周 最后一天日期
  7. 7款同步备份手机通讯录工具
  8. 驱动级键盘记录器 干什么用
  9. AVG杀毒软件是流氓软件,难以彻底干净卸载,会在系统里埋钩子(附卸载方法)
  10. 求链表的倒数第N个节点