【树状数组套主席树】带修改区间K大数
P2617 Dynamic Rankings
题目描述
给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。
输入输出格式
输入格式:
第一行有两个正整数n(1≤n≤100000),m(1≤m≤100000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t
Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。
C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。
输出格式:
对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。输入输出样例
输入样例#1:
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
输出样例#1:
3
6
说明
10%的数据中,m,n≤100;20%的数据中,m,n≤1000;
50%的数据中,m,n≤10000。
对于所有数据,m,n≤100000
请注意常数优化,但写法正常的整体二分和树套树都可以以大约1000ms每个点的时间过。
来源:bzoj1901
本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。
一些奇怪的东西
这个大概是luogu某题目,然而我太菜了,所以现在才会做。
这个题目显然是由一些静态的东西衍生而来的(没错就是静态区间K大数)
Hmm...昨天(可能是今天??)有人问我,一些静态和动态的问题,我列举一下:
静态区间K大数(排个序就好了)
静态区间K大数(主席树搞一搞)
待修改区间K大数(我就要讲的这个嘛)
动态区间和(zkw线段树/朴素线段树/2个树状数组)
静态区间和(...前缀和?)
步入正题
话说带修改区间K大数(注意是修改而并不是插入)
显然我们如果按照静态区间K大数的方法搞,暴力更新整棵线段树那么复杂度将是O(n log2 n)修改每次
想到单点修改求前缀和想到树状数组。不妨用树状数组维护线段树每个节点的前缀和,
换句话说要想求得每个节点具体的值,那么必须将属于这个节点的log2 n个节点的和全部累加,才是这个节点值域范围内,前缀插入数的个数
既然我们能求出在线段树某一节点值域范围内,前缀插入数的个数,我们就按照和静态区间K大数的类二分查找(用线段树对值域的二分代替整体二分)来找到一个对于的树根,输出他的标号就行。
所以,树状数组是维护一个数组表示的是要想知道当前每一节点值域是[L,R]前缀插入数的个数,是哪log2 n个节点的累加和。
这样子复杂度是O(log22n)每次插入。
查询的时候也是这样用R的前缀插入数的个数减去(l-1)前缀插入数的个数,就是该节点值域在[L,R]区间内插入数的个数。
这样的复杂度也是O(log22n)每次查询。
注意一些细节:
记录那几个点的数组(node_add和node_cut只需开log2n个即可),
然后离线离散化以后在线做(其实和在线效果一样),
然后离散化的时候尽量不用vector(不好习惯)
对tmp[]离散化,T记录离散化后下标
sort(tmp+,tmp++tmp[]);
T=unique(tmp+,tmp++tmp[])-tmp-1;
若要查询某个数val离散化以后是多少,那么就是
w=lower_bound(tmp+,tmp++T,val)-tmp;
若要查询某个离散化后的数kkk实际上是多少那么直接访问下标
w=tmp[kkk];
还是得解释代码:
# include <cstdio>
# include <map>
# include <algorithm>
# include <vector>
# include <cstring>
using namespace std;
const int N=1e5+;
# define lowbit(x) (x&(-x))
# define lson t[rt].ls,l,mid
# define rson t[rt].rs,mid+,r
# define mid ((l+r)>>)
int tmp[N<<];
struct rec{
int l,r,k,o;
}qes[N];
struct Seqment_Tree{
int ls,rs,val;
}t[N*];//树套树空间得开 n log n
int node_cut[],node_add[]; //这里只要log n个就行后面memset会慢
int cnt_cut,cnt_add,tot;
int root[N],a[N];
int T,n,m;
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void write(int x)
{
if (x<) x=-x,putchar('-');
if (x>) write(x/);
putchar(''+x%);
}//I/O优化
void update(int &rt,int l,int r,int pos,int val)
{
if (!rt) rt=++tot; //如果此时的访问空的节点那么建立节点,否则会覆盖掉原有节点信息(普通主席树最好也这么写,但是没必要,因为每个节点一定是空的!!!)
t[rt].val+=val;
if (l==r) return;
if (pos<=mid) update(lson,pos,val);
else update(rson,pos,val);
}//普通主席树的更改维护,值域+1/-1
void pre_update(int x,int val)
{
int w=lower_bound(tmp+,tmp++T,a[x])-tmp;
for (int i=x;i<=n;i+=lowbit(i)) update(root[i],,T,w,val);
}//首先处理出那几棵线段树管这个数组的位置的前缀和的,然后每个线段树分别维护
int query(int l,int r,int k)
{
if (l==r) return l;
int ret=;
for (int i=;i<=cnt_add;i++)
ret+=t[t[node_add[i]].ls].val;
for (int i=;i<=cnt_cut;i++)
ret-=t[t[node_cut[i]].ls].val;
//该加的加(r),该减的减(l-1)
if (k<=ret) {
for (int i=;i<=cnt_add;i++)
node_add[i]=t[node_add[i]].ls;
for (int i=;i<=cnt_cut;i++)
node_cut[i]=t[node_cut[i]].ls;
return query(l,mid,k);
//不足右边不可能往左边搜
} else {
for (int i=;i<=cnt_add;i++)
node_add[i]=t[node_add[i]].rs;
for (int i=;i<=cnt_cut;i++)
node_cut[i]=t[node_cut[i]].rs;
return query(mid+,r,k-ret);
//超过左边不可能往右边搜
}
}
int pre_query(int l,int r,int k)
{
memset(node_add,,sizeof(node_add));
memset(node_cut,,sizeof(node_cut));
cnt_add=cnt_cut=;//清空
for (int i=r;i;i-=lowbit(i)) node_add[++cnt_add]=root[i];
//处理该加的根节点
for (int i=l-;i;i-=lowbit(i)) node_cut[++cnt_cut]=root[i];
//处理该减的根节点
return query(,T,k);
}
int main()
{
n=read();m=read();
for (int i=;i<=n;i++)
tmp[++tmp[]]=a[i]=read();
for (int i=;i<=m;i++) {
char ch=;
while (ch!='Q'&&ch!='C') ch=getchar();
if (ch=='Q') qes[i].l=read(),qes[i].r=read(),qes[i].k=read(),qes[i].o=;
else qes[i].l=read(),tmp[++tmp[]]=qes[i].r=read(),qes[i].o=;
}
sort(tmp+,tmp++tmp[]);
T=unique(tmp+,tmp++tmp[])-tmp;
for (int i=;i<=n;i++) pre_update(i,);
for (int i=;i<=m;i++) {
if (qes[i].o==) {
write(tmp[pre_query(qes[i].l,qes[i].r,qes[i].k)]);
putchar('\n');
} else {
pre_update(qes[i].l,-);
a[qes[i].l]=qes[i].r;
pre_update(qes[i].l,);
}
}
return ;
}
【树状数组套主席树】带修改区间K大数的更多相关文章
- ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解
题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树
[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...
- BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树
[题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...
- BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树
BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...
- P2617 Dynamic Rankings(树状数组套主席树)
P2617 Dynamic Rankings 单点修改,区间查询第k大 当然是无脑树套树了~ 树状数组套主席树就好辣 #include<iostream> #include<cstd ...
- [COGS257]动态排名系统 树状数组套主席树
257. 动态排名系统 时间限制:5 s 内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[ ...
- Codeforces Round #404 (Div. 2) E. Anton and Permutation(树状数组套主席树 求出指定数的排名)
E. Anton and Permutation time limit per test 4 seconds memory limit per test 512 megabytes input sta ...
- 【Luogu】P2617Dynamic Ranking(树状数组套主席树)
题目链接 树状数组套主席树有点难懂qwq 不好理解 树状数组套主席树的直观理解应该是:树状数组的每一个节点是一棵主席树. 普通区间修改我们是创建1个线段树,树状数组套主席树的时候我们就创建log个线段 ...
- BZOJ 2141 排队(树状数组套主席树)
解法很多的题,可以块套树状数组,可以线段树套平衡树.我用的是树状数组套主席树. 题意:给出一段数列,m次操作,每次操作是交换两个位置的数,求每次操作后的逆序对数.(n,m<=2e4). 对于没有 ...
随机推荐
- 网络对抗技术 2017-2018-2 20155215 Exp9 Web安全基础
1.实践过程 前期准备:WebGoat WebGoat分为简单版和开发板,简单版是个Java的Jar包,只需要有Java环境即可,我们在命令行里执行java -jar webgoat-containe ...
- 基于vue全家桶制作的移动端音乐WebApp
Vue.js 2.0实战项目 基于Vue + Vuex + Vue-router + Webpack 2.0 打造移动端音乐WebAPP,实现了轮播图.音乐推荐.歌手列表.音乐搜索.注册等功能. 技术 ...
- 委托、多播委托(MulticastDelegate)
委托.多播委托(MulticastDelegate) 多播委托(MulticastDelegate)继承自 Delegate ,表示多路广播委托:即,其调用列表中可以拥有多个元素的委托.实际上,我们自 ...
- CSS快速入门-属性和伪类
一.属性选择器 <div class="gradefather"> hello1 <div name="son">hello2 < ...
- 基于Vue手写一个下拉刷新
当然不乏有很多下拉刷新的插件可以直接使用,但是自定义程度不强,大部分都只能改改文字,很难满足设计师的创意,譬如淘宝和京东首页那种效果,就需要自己花心思倒腾了,最近刚好有这种需求,做完了稍微总结一下,具 ...
- 「功能笔记」Spacemacs+Evil备忘录
设置代理 (setq url-gateway-method 'socks) (setq socks-server '("Default server" "127.0.0. ...
- flask入门小方法
我是在pycharm中写的.那么需要在Termainal中cd 到当前文件所在的文件夹,在运行python py文件名 一开始想用面向对象的方法来封装这些小模块,但发现在面向对象中要用到类属性,以及类 ...
- 教你用PS制作雨天窗户上透明水滴字
雨天窗户上透明水滴字制作方法很简单,主要利用图层样式来实现.学习后可以让你对图层样式有更好的了解,认识. 先看下完成后的效果图: 步骤1: 在Photoshop中我们新建或Ctrl+N,创建1920x ...
- Redis源码阅读(二)高可用设计——复制
Redis源码阅读(二)高可用设计-复制 复制的概念:Redis的复制简单理解就是一个Redis服务器从另一台Redis服务器复制所有的Redis数据库数据,能保持两台Redis服务器的数据库数据一致 ...
- Go语言实现数据结构(一)单链表
1.基本释义 2.结构体设计 3.基本方法设计 4.Main函数测试 1. 基本释义 线性表包含两种存储方法:顺序存储结构和链式存储结构,其中顺序表的缺点是不便插入与删除数据:接下来我们重点实现基于G ...