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大数的更多相关文章

  1. ZOJ 2112 Dynamic Rankings(树状数组套主席树 可修改区间第k小)题解

    题意:求区间第k小,节点可修改 思路:如果直接用静态第k小去做,显然我更改一个节点后,后面的树都要改,这个复杂度太高.那么我们想到树状数组思路,树状数组是求前缀和,那么我们可以用树状数组套主席树,求出 ...

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

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

  3. BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

    [题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> ...

  4. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  5. BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树

    BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...

  6. P2617 Dynamic Rankings(树状数组套主席树)

    P2617 Dynamic Rankings 单点修改,区间查询第k大 当然是无脑树套树了~ 树状数组套主席树就好辣 #include<iostream> #include<cstd ...

  7. [COGS257]动态排名系统 树状数组套主席树

    257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[ ...

  8. 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 ...

  9. 【Luogu】P2617Dynamic Ranking(树状数组套主席树)

    题目链接 树状数组套主席树有点难懂qwq 不好理解 树状数组套主席树的直观理解应该是:树状数组的每一个节点是一棵主席树. 普通区间修改我们是创建1个线段树,树状数组套主席树的时候我们就创建log个线段 ...

  10. BZOJ 2141 排队(树状数组套主席树)

    解法很多的题,可以块套树状数组,可以线段树套平衡树.我用的是树状数组套主席树. 题意:给出一段数列,m次操作,每次操作是交换两个位置的数,求每次操作后的逆序对数.(n,m<=2e4). 对于没有 ...

随机推荐

  1. 关于NLB的群集操作模式知识 (转载)

    单播:单播模式是指各节点的网络适配器被重新指定了一个虚拟MAC(由02-bf和群集IP地址组成确保此MAC的唯一性).由于所有绑定群集的网络适配器的MAC都相同,所以在单网卡的情况下,各节点之间是不能 ...

  2. 2017-2018-2 20155203《网络对抗技术》Exp9 :Web安全基础

    实践过程记录 - SQL Injection(Webgoat 8.0&Webgoat7.0) 1. SQL Injection(Webgoat 8.0). 这一部分很基础,是简单的sql注入, ...

  3. 2017-2018 Exp3 MAL_免杀原理与实践 20155214

    目录 Exp3 MAL_免杀原理与实践 实验内容 对msf生成后门程序的检测 Veil-Evasion应用 Visual Studio2017 + shellcode生成后门 主要思路 知识点 最后的 ...

  4. 浅谈Objeact.clone克隆(纯个人理解,如有错误请指正)

    现在先来看一下jdk给出的Object.clone源码和注释 /** * Creates and returns a copy of this object. The precise meaning ...

  5. OFS环境,删除Resource 时出现错误失败,应该如何继续

    From the Windows failover cluster manager,select the group listener, stop it, and delete it.  Do the ...

  6. 汇编 push ,pop指令

    知识点:  PUSH  POP  CALL堆栈平衡  RETN指令 一.PUSH入栈指令 (压栈指令): 格式: PUSH 操作数 //sub esp,4 ;mov [esp],EBP 操作数 ...

  7. 命令行模式和python交互模式

    一.命令行模式 在Windows开始菜单选择“命令提示符”,就进入到命令行模式,它的提示符类似C:>:. 二.Python交互模式 在命令行模式下敲命令python,就看到类似如下的一堆文本输出 ...

  8. R绘图 第八篇:绘制饼图(ggplot2)

    geom_bar()函数不仅可以绘制条形图,还能绘制饼图,跟绘制条形图的区别是坐标系不同,绘制饼图使用的坐标系polar,并且设置theta="y": coord_polar(th ...

  9. 2、Arx二次开发创建第一个应用程序

    一.本节课程 Arx二次开发创建第一个应用程序 二.本节要讲解的知识点 1.手动创建ARX的应用的步骤. 2.应用向导创建ARX应用程序的步骤. 三.具体内容 1.需求:创建一个Hello World ...

  10. 粒子群算法(PSO)算法解析(简略版)

    粒子群算法(PSO) 1.粒子群算法(PSO)是一种基于群体的随机优化技术: 初始化为一组随机解,通过迭代搜寻最优解. PSO算法流程如图所示(此图是从PPT做好,复制过来的,有些模糊) 2.PSO模 ...