题意:n个数,q个询问 (n<=50000, q<=10000)

Q x y z 代表询问[x, y]区间里的第z小的数

C x y    代表将(从左往右数)第x个数变成y

上篇介绍了在[x, y]区间内查询第z小的数的方法(静态主席树)

本题有更新操作

若仍用上篇的做法,

每次更新一个数,需要更新的是T[i], T[i+1]... ...T[n](该数所在的树以及它后面的所有树)

因为每棵树T[i]所记录的都是前缀(1到i的数出现的次数) 因此,改变i,会影响i到n的所有树

这样,每次更新的复杂度最坏为O($n$),最坏更新q次即为O($n\times m$) 复杂度相当庞大,很明显这样做是不行的

那怎么办呢?

我们可以发现,对于改变i处的数这个操作,对于T[i], T[i+1]... ...T[n]这些树的影响是相同的

都只改变了  “原来i处的数 的数量”  和  “现在i处的数 的数量” 这两个值而已

我们只要在原来的基础上增加一类树, 用它们来维护更新掉的数

即用树状数组来记录更新,每次更新$logn$棵树

下面来演示一下建树到查询的过程:

比如此题的第一个案例


Q
C
Q

先将序列以及要更新的数(C操作)离散化

即3 2 1 4 7 、 6  ---->(排序) ----> 1 2 3 4 6 7

那么我们就需要建一棵这样的树:

(圈里的都是结点的编号, 4、5、6、9、10、11号结点代表的分别是1、2、3、4、6、7)

(4、5、9、10你也可以任意作为6或11的儿子, 递归生成的是类似这样的, 这并不重要)

对于3 2 1 4 7(先不管需要更新的6)建完树见下图(建树过程同静态的,不明白的戳这里,上篇博客有讲)

(红色的是个数, 相同结点的个数省略了,同前一棵树)

对于C操作之前的Q,就跟静态的类似,减一减 找就好了

然后下面要更新了

对于更新, 我们不改变这些已经建好的树, 而是另建一批树S,用来记录更新,而这批线段树,我们用树状数组来维护

也就是树状数组的每个节点都是一颗线段树

一开始,S[0]、S[1]、S[2]、S[3]、S[4]、S[5](树状数组的每个节点)这些都与T[0]相同(也就是每个节点建了一棵空树)

对于C 2 6 这个操作, 我们只需要减去一个2,加上一个6即可

对于减去2

(树状数组i+lowbit(i)为i的父亲节点, 修改i,就要把i的所有父亲节点都修改了)

2在树状数组中出现的位置是 2、2+lowbit(2)=4 这两个位置,

因此要更新的是S[2]和S[4]这两个节点中的树

删去2后是这样

加上一个6 (同样是对于2号位置, 因此需要更新的仍是S[2]和S[4])

加上之后是这样

当查询的时候, 对树T的操作与静态的一致,另外再加上S树的值就好了

 #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define lson l, m
#define rson m+1, r
const int N=;
int a[N], Hash[N];
int T[N], L[N<<], R[N<<], sum[N<<];
int S[N];
int n, m, tot;
struct node
{
int l, r, k;
bool Q;
}op[]; int build(int l, int r)
{
int rt=(++tot);
sum[rt]=;
if(l!=r)
{
int m=(l+r)>>;
L[rt]=build(lson);
R[rt]=build(rson);
}
return rt;
} int update(int pre, int l, int r, int x, int val)
{
int rt=(++tot);
L[rt]=L[pre], R[rt]=R[pre], sum[rt]=sum[pre]+val;
if(l<r)
{
int m=(l+r)>>;
if(x<=m)
L[rt]=update(L[pre], lson, x, val);
else
R[rt]=update(R[pre], rson, x, val);
}
return rt;
} int lowbit(int x)
{
return x&(-x);
} int use[N];
void add(int x, int pos, int val)
{
while(x<=n)
{
S[x]=update(S[x], , m, pos, val);
x+=lowbit(x);
}
} int Sum(int x)
{
int ret=;
while(x>)
{
ret+=sum[L[use[x]]];
x-=lowbit(x);
}
return ret;
} int query(int u, int v, int lr, int rr, int l, int r, int k)
{
if(l>=r)
return l;
int m=(l+r)>>;
int tmp=Sum(v)-Sum(u)+sum[L[rr]]-sum[L[lr]];
if(tmp>=k)
{
for(int i=u;i;i-=lowbit(i))
use[i]=L[use[i]];
for(int i=v;i;i-=lowbit(i))
use[i]=L[use[i]];
return query(u, v, L[lr], L[rr], lson, k);
}
else
{
for(int i=u;i;i-=lowbit(i))
use[i]=R[use[i]];
for(int i=v;i;i-=lowbit(i))
use[i]=R[use[i]];
return query(u, v, R[lr], R[rr], rson, k-tmp);
}
} void modify(int x, int p, int d)
{
while(x<=n)
{
S[x]=update(S[x], , m, p, d);
x+=lowbit(x);
}
} int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int q;
scanf("%d%d", &n, &q);
tot=;
m=;
for(int i=;i<=n;i++)
{
scanf("%d", &a[i]);
Hash[++m]=a[i];
}
for(int i=;i<q;i++)
{
char s[];
scanf("%s", s);
if(s[]=='Q')
{
scanf("%d%d%d", &op[i].l, &op[i].r, &op[i].k);
op[i].Q=;
}
else
{
scanf("%d%d", &op[i].l, &op[i].r);
op[i].Q=;
Hash[++m]=op[i].r;
}
}
sort(Hash+, Hash++m);
int mm=unique(Hash+, Hash++m)-Hash-;
m=mm;
T[]=build(, m);
for(int i=;i<=n;i++)
T[i]=update(T[i-], , m, lower_bound(Hash+, Hash++m, a[i])-Hash, );
for(int i=;i<=n;i++)
S[i]=T[];
for(int i=;i<q;i++)
{
if(op[i].Q)
{
for(int j=op[i].l-;j;j-=lowbit(j))
use[j]=S[j];
for(int j=op[i].r;j;j-=lowbit(j))
use[j]=S[j];
printf("%d\n", Hash[query(op[i].l-, op[i].r, T[op[i].l-], T[op[i].r], , m, op[i].k)]);
}
else
{
modify(op[i].l, lower_bound(Hash+, Hash++m, a[op[i].l])-Hash, -);
modify(op[i].l, lower_bound(Hash+, Hash++m, op[i].r)-Hash, );
a[op[i].l]=op[i].r;
}
}
}
return ;
}

ZOJ 2112

[主席树]ZOJ2112 && BZOJ1901 Dynamic Rankings的更多相关文章

  1. ZOJ2112 BZOJ1901 Dynamic Rankings 树套树 带修改的区间第k小

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 树套树,线段树套splay或者主席树套树状数组,我抄了一下hzwer ...

  2. bzoj1901&zoj2112&cogs257 Dynamic Rankings(动态排名系统)

    bzoj1901&zoj2112&cogs257 Dynamic Rankings(动态排名系统) cogs zoj bzoj-权限 题解 bzoj和zoj都是骗访问量的233,我没有 ...

  3. 少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

    少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写 ...

  4. BZOJ1901 - Dynamic Rankings(树状数组套主席树)

    题目大意 给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下: Q l r k 要求你查询区间[l,r]第k小的数是哪个 C i t  要求你把第i个数修改为t 题解 动态的区间第k ...

  5. BZOJ1901 Dynamic Rankings|带修主席树

    题目链接:戳我 其实我并不会做,于是看了题解 我们都知道主席树是利用前缀和记录历史版本来搞区间K大的一种数据结构.不过一般的主席树只能搞定静态区间第K大.如果带修怎么办呢? 想一下...单点修改+区间 ...

  6. 主席树初探--BZOJ1901: Zju2112 Dynamic Rankings

    n<=10000的序列做m<=10000个操作:单点修改,查区间第k小. 所谓的主席树也就是一个值域线段树嘛..不过在这里还是%%fotile 需要做一个区间查询,由于查第k小,需要一些能 ...

  7. [BZOJ1901]Dynamic Rankings

    Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数 ...

  8. ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

  9. zoj2112 主席树动态第k大 (主席树&&树状数组)

    Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB The Company Dynamic Rankings has ...

随机推荐

  1. Mentor PADS 9.5下载安装及破解指南

    Pads,是一款用于设计.模拟电子线路及设计电路板的电脑软件,原由Innoveda公司开发,其后改名为PowerPCB,在2002年4月Innoveda被Mentor Graphics收购,近年再次改 ...

  2. shell脚本初识

    #!/bin/bash(linux脚本环境的声明即解释器,该解释器为bash,位于根目录下的bin目录下) 变量的定义与赋值: 格式:变量名=变量值(无需声明变量类型) 变量的引用: 格式:$变量名 ...

  3. 打造自己的3D全景漫游

    three.js 示例: ​ 打造H5里的"3D全景漫游"秘籍 - 腾讯ISUX ​ QQ物联星球计划 通过pano2vr直接将鱼眼全景图生成立体空间的六个面:也可通过Photos ...

  4. 配置Windows 2008 R2 64位 Odoo 8.0/9.0 源码开发调试环境

    安装过程中,需要互联网连接下载python依赖库: 1.安装: Windows Server 2008 R2 x64标准版 2.安装: Python 2.7.10 amd64 到C:\Python27 ...

  5. 生动有趣的动画Toast--第三方开源--NiftyNotification

    NiftyNotification在github上的项目主页是:https://github.com/sd6352051/NiftyNotificationNiftyNotification本身又依赖 ...

  6. DataSnap数据库连接池,数据集对象池的应用

    传统的应用服务器的开发往往是在ServerMethods单元中拖放一堆TDataSet, TDaTaSetProvider控件,这是一个最简单粗暴的开发方向,往往会造成服务端程序文件的臃肿.服务运行期 ...

  7. 《.NET简单企业应用》项目开发环境

    项目开始,开发团队需要构建一套开发环境,主要包含:开发工具.代码管理/版本控制系统.任务和Bug管理系统和持续集成(CI)系统.本文主要列举项目开发中经常使用的开发工具和第三方库. 本文所列工具根据前 ...

  8. 【转】为什么我说 Android 很糟糕

    http://zhuanlan.zhihu.com/wooyun/19879016 Android 的安全问题一直被吐槽,包括不安全的APP市场.上次的远程命令执行漏洞.还有它的权限机制,总之一团糟, ...

  9. cadence 机械孔的制作

    在平时画PCB的时候,会用到安装孔,好多人就是找个过孔,在原理图中连接GND,这样使用也可以,下面介绍一种正经机械孔的制作方法(自己摸索的),制作一个孔径为3mm的安装孔. 1 打开pad desig ...

  10. Java从入门到精通——数据库篇之JAVA中的对Oracle数据库操作

    在Java中对Oracle数据库的操作分为两种:一.查询.二.非查询. 下面是我对其进行总结: 一.查询数据 /** * 根据用户代码查询 * @param userId * @return 如果存在 ...