Dynamic Rankings ZOJ - 2112(主席树+树状数组)
The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.
Your task is to write a program for this computer, which
- Reads N numbers from the input (1 <= N <= 50,000)
- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.
Input
The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.
The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format
Q i j k or
C i t
It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.
There're NO breakline between two continuous test cases.
Output
For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])
There're NO breakline between two continuous test cases.
Sample Input
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
3
6
参考了大佬的博客:https://www.cnblogs.com/Empress/p/4659824.html
题意就是求区间内的第 k 小的数,但是会改变区间里的数。
因为数很大,所以首先要把所有的 a[i] ,包括更新过程的 a[i],然后拿去离散化。
对于求区间第 k 大,基本思想还是和静态区间求第 k 小一样,先求前缀和,然后相减。然后得到区间内的数量关系,就可以求区间内的第 k 小了。但是这里有更新操作,原本的求区间的 node[node[y].l].sum - node[node[x].l].sum 就不能直接用了。
这里我们维护两颗完全不同的树,对一开始的数列用普通的主席树来维护,对于更新操作,用一个树状数组来维护,树状数组的每个节点都是一颗树,因为是单点更新,每棵树都只要更新 log(n) 个节点,用主席树来更新。(一个只维护初始的样子,一个只维护更新的样子)
然后这样的话,我们只需要想办法求出在 R 树和 L 树在某个区间上的左边部分的差值,在加上 node[node[y].l].sum - node[node[x].l].sum,就可以确定第 k 小在这个区间的左边还是右边。然后就可以开始用主席树的套路了。
然后这里为了求 R 树和 L 树在某个区间内的差值,我们定义一个 use 表示树状数组的目前结点对应的树是哪一颗,use 的更新类似于主席树递归时候从x -> node[x].l 这样子的过程,都是为了把它往左整体往左更新。.......其实还是感觉很抽象的东西
/*
.
';;;;;.
'!;;;;;;!;`
'!;|&#@|;;;;!:
`;;!&####@|;;;;!:
.;;;!&@$$%|!;;;;;;!'.`:::::'.
'!;;;;;;;;!$@###&|;;|%!;!$|;;;;|&&;.
:!;;;;!$@&%|;;;;;;;;;|!::!!:::;!$%;!$%` '!%&#########@$!:.
;!;;!!;;;;;|$$&@##$;;;::'''''::;;;;|&|%@$|;;;;;;;;;;;;;;;;!$;
;|;;;;;;;;;;;;;;;;;;!%@#####&!:::;!;;;;;;;;;;!&####@%!;;;;$%`
`!!;;;;;;;;;;!|%%|!!;::;;|@##%|$|;;;;;;;;;;;;!|%$#####%;;;%&;
:@###&!:;;!!||%%%%%|!;;;;;||;;;;||!$&&@@%;;;;;;;|$$##$;;;%@|
;|::;;;;;;;;;;;;|&&$|;;!$@&$!;;;;!;;;;;;;;;;;;;;;;!%|;;;%@%.
`!!;;;;;;;!!!!;;;;;$@@@&&&&&@$!;!%|;;;;!||!;;;;;!|%%%!;;%@|.
%&&$!;;;;;!;;;;;;;;;;;|$&&&&&&&&&@@%!%%;!||!;;;;;;;;;;;;;$##!
!%;;;;;;!%!:;;;;;;;;;;!$&&&&&&&&&&@##&%|||;;;!!||!;;;;;;;$&:
':|@###%;:;;;;;;;;;;;;!%$&&&&&&@@$!;;;;;;;!!!;;;;;%&!;;|&%.
!@|;;;;;;;;;;;;;;;;;;|%|$&&$%&&|;;;;;;;;;;;;!;;;;;!&@@&'
.:%#&!;;;;;;;;;;;;;;!%|$$%%&@%;;;;;;;;;;;;;;;;;;;!&@:
.%$;;;;;;;;;;;;;;;;;;|$$$$@&|;;;;;;;;;;;;;;;;;;;;%@%.
!&!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;|@#;
`%$!;;;;;;;;;;;$@|;;;;;;;;;;;;;;;;;;;;;;;;!%$@#@|.
.|@%!;;;;;;;;;!$&%||;;;;;;;;;;;;;;;;;!%$$$$$@#|.
;&$!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;%#####|.
|##$|!;;;;;;::'':;;;;;;;;;;;;;!%$$$@#@;
;@&|;;;;;;;::'''''':;;;;;;;|$&@###@|`
.%##@|;;;;:::''''''''''::;!%&##$'
`$##@$$@@&|!!;;;:'''''::::;;;;;|&#%.
;&@##&$%!;;;;;;::''''''''::;!|%$@#@&@@:
.%@&$$|;;;;;;;;;;:'''':''''::;;;%@#@@#%.
:@##@###@$$$$$|;;:'''':;;!!;;;;;;!$#@@#$;`
`%@$$|;;;;;;;;:'''''''::;;;;|%$$|!!&###&'
|##&%!;;;;;::''''''''''''::;;;;;;;!$@&:`!'
:;!@$|;;;;;;;::''''''''''':;;;;;;;;!%&@$: !@#$'
|##@@&%;;;;;::''''''''':;;;;;;;!%&@#@$%: '%%!%&;
|&%!;;;;;;;%$!:''''''':|%!;;;;;;;;|&@%||` '%$|!%&;
|@%!;;!!;;;||;:'''''':;%$!;;;;!%%%&#&%$&: .|%;:!&%`
!@&%;;;;;;;||;;;:''::;;%$!;;;;;;;|&@%;!$; `%&%!!$&:
'$$|;!!!!;;||;;;;;;;;;;%%;;;;;;;|@@|!$##; !$!;:!$&:
|#&|;;;;;;!||;;;;;;;;!%|;;;;!$##$;;;;|%' `%$|%%;|&$'
|&%!;;;;;;|%;;;;;;;;$$;;;;;;|&&|!|%&&; .:%&$!;;;:!$@!
`%#&%!!;;;;||;;;;;!$&|;;;!%%%@&!;;;!!;;;|%!;;%@$!%@!
!&!;;;;;;;;;||;;%&!;;;;;;;;;%@&!;;!&$;;;|&%;;;%@%`
'%|;;;;;;;;!!|$|%&%;;;;;;;;;;|&#&|!!||!!|%$@@|'
.!%%&%'`|$; :|$#%|@#&;%#%.
*/
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
#define INOPEN freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout) typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 5e4 + ;
const int maxm = 1e5 + ;
const ll mod = 1e9 + ;
const ll INF = 1e18 + ;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-;
using namespace std; int n, m;
int cas, tol, T;
struct Node{
int l, r;
int sum;
} node[maxn * ];
struct Ask{
int l, r, k;
int id;
} ask[maxn / ];
int a[maxn];
int S[maxn]; //树状数组的根
int rt[maxn]; //主席树的根
int use[maxn]; //use表示树状数组的各个结点对应的树是哪一颗
vector<int> vv;
int L, R; int getid(int x) {
return lower_bound(vv.begin(), vv.end(), x) - vv.begin() + ;
} void init() {
tol = ;
mes(a, );
mes(S, );
mes(rt, );
vv.clear();
mes(use, );
mes(ask, );
mes(node, );
} int Sum(int pos) {
// 各颗树从 S[i] 走到了 used[i] 的位置,然后求左边部分的和
int ans = ;
for(int i=pos; i; i-=lowbit(i))
ans += node[node[use[i]].l].sum;
return ans;
} void update(int l, int r, int &x, int y, int pos, int val) {
x = ++tol;
node[tol] = node[y];
node[tol].sum += val;
if(l == r) return ;
int mid = (l + r) >> ;
if(pos <= mid)
update(l, mid, node[x].l, node[y].l, pos, val);
else
update(mid+, r, node[x].r, node[y].r, pos, val);
} void add(int pos, int k, int v) {
for(int i=pos; i<=n; i+=lowbit(i)) {
update(, vv.size(), S[i], S[i], k, v);
}
} int query(int l, int r, int x, int y, int k) {
if(l == r) return l;
int mid = (l + r) >> ;
//注意树状数组是 L 和 R
//因为是找 L 和 R 树链上的到达 use 位置的值
int tmp = Sum(R) - Sum(L) + node[node[y].l].sum - node[node[x].l].sum;
if(k <= tmp) {
//往现在到达的x,y位置的两棵树的左边查询
//把 L 和 R 这路径上的所有树状数组都往左子树更新
for(int i=L; i; i-=lowbit(i)) use[i] = node[use[i]].l;
for(int i=R; i; i-=lowbit(i)) use[i] = node[use[i]].l;
return query(l, mid, node[x].l, node[y].l, k);
} else {
//往现在到达的x,y位置的两棵树的右边查询
//把 L 和 R 这路径上的所有树状数组都往右子树更新
for(int i=L; i; i-=lowbit(i)) use[i] = node[use[i]].r;
for(int i=R; i; i-=lowbit(i)) use[i] = node[use[i]].r;
return query(mid+, r, node[x].r, node[y].r, k-tmp);
}
} int main() {
scanf("%d", &T);
while(T--) {
init();
scanf("%d%d", &n, &m);
for(int i=; i<=n; i++) {
scanf("%d", &a[i]);
vv.push_back(a[i]);
}
for(int i=; i<=m; i++) {
char ss[];
scanf("%s", ss);
if(ss[] == 'Q') {
ask[i].id = ;
scanf("%d%d%d", &ask[i].l, &ask[i].r, &ask[i].k);
} else {
ask[i].id = ;
scanf("%d%d", &ask[i].l, &ask[i].r);
vv.push_back(ask[i].r);
}
}
sort(vv.begin(), vv.end()); //离散化一下
vv.erase(unique(vv.begin(), vv.end()), vv.end());
for(int i=; i<=n; i++) {
int id = getid(a[i]); //第一颗树
update(, vv.size(), rt[i], rt[i-], id, );
//vv里面的数可能不止有 n 个,切记不可以用 n
}
for(int i=; i<=m; i++) {
if(ask[i].id) {
L = ask[i].l-, R = ask[i].r;
//从 L 和 R 位置开始, use 表示的从 L, R 的S根开始
for(int j=L; j; j-=lowbit(j)) use[j] = S[j];
for(int j=R; j; j-=lowbit(j)) use[j] = S[j];
int pos = query(, vv.size(), rt[L], rt[R], ask[i].k);
printf("%d\n", vv[pos-]);
} else { //第二颗树
int id = getid(a[ask[i].l]);
add(ask[i].l, id, -); //先把之前的清除掉,在加现在的
id = getid(ask[i].r);
add(ask[i].l, id, );
a[ask[i].l] = ask[i].r;
}
}
}
return ;
}
Dynamic Rankings ZOJ - 2112(主席树+树状数组)的更多相关文章
- 动态主席树【带修改】&& 例题 Dynamic Rankings ZOJ - 2112
参考链接:https://blog.csdn.net/WilliamSun0122/article/details/77885781 一.动态主席树介绍 动态主席树与静态主席树的不同在于:静态主席树不 ...
- 洛谷 P2617 Dynamic Rankings || ZOJ - 2112
写的让人看不懂,仅留作笔记 静态主席树,相当于前缀和套(可持久化方法构建的)值域线段树. 建树方法:记录前缀和的各位置的线段树的root.先建一个"第0棵线段树",是完整的(不需要 ...
- ZOJ - 2112 主席树套树状数组
题意:动态第k大,可单点更新,操作+原数组范围6e4 年轻人的第一道纯手工树套树 静态第k大可以很轻易的用权值主席树作差而得 而动态第k大由于修改第i个数会影响[i...n]棵树,因此我们不能在原主席 ...
- BZOJ1901 Dynamic Rankings|带修主席树
题目链接:戳我 其实我并不会做,于是看了题解 我们都知道主席树是利用前缀和记录历史版本来搞区间K大的一种数据结构.不过一般的主席树只能搞定静态区间第K大.如果带修怎么办呢? 想一下...单点修改+区间 ...
- BZOJ 1901: Zju2112 Dynamic Rankings | 带修改主席树
题目: emmmm是个权限题 题解: 带修改主席树的板子题,核心思想是用树状数组维护动态前缀和的性质来支持修改 修改的时候修改类似树状数组一样进行logn个Insert 查询的时候同理,树状数组的方法 ...
- [luogu P2617] Dynamic Rankings 带修主席树
带修改的主席树,其实这种,已经不能算作主席树了,因为这个没有维护可持久化的... 主席树直接带修改的话,由于这种数据结构是可持久化的,那么要相应改动,这个节点以后所有的主席树,这样单次修改,就达到n* ...
- 【BZOJ-1901】Dynamic Rankings 带修主席树
1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 7292 Solved: 3038[Su ...
- bzoj1901: Zju2112 Dynamic Rankings(BIT套主席树)
带修改的题主席树不记录前缀,只记录单点,用BIT统计前缀. 对于BIT上每一个点建一棵主席树,修改和询问的时候用BIT跑,在主席树上做就行了. 3k4人AC的题#256...应该不算慢 #incl ...
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
随机推荐
- 想要在launcher中模拟按home键。
Intent mHomeIntent = new Intent(Intent.ACTION_MAIN); mHomeIntent.addCategory(Intent.CATEGORY_HOME); ...
- 如何正确使用Espresso来测试你的Android程序
UI测试在Android平台上一直都是一个令人头痛的事情, 由于大家平时用的很少, 加之很多文档的缺失, 如果很多东西从头摸索,势必踩坑无数. 自Android24正式淘汰掉了Instrumentat ...
- GenericServlet 、Servlet和httpServler
-------[转] 1.GenericServlet类是所有Servlet类的祖先类. 2.HttpServlet类继承了GenericServlet类. 3.Servlet有两个非常重要的的对象, ...
- TinScrapy-简化的Scrapy原码-查看爬虫的执行流程
学习了自定义的TinyScrapy框架,整理出以下定注释的代码 from twisted.web.client import getPage,defer from twisted.internet i ...
- MyBatis学习总结_Mybatis查询之resultMap和resultType区别
MyBatis的每一个查询映射的返回类型都是ResultMap,只是当我们提供的返回类型属性是resultType的时候,MyBatis对自动的给我们把对应的值赋给resultType所指定对象的属性 ...
- Java 集合系列(四)—— ListIterator 源码分析
以脑图的形式来展示Java集合知识,让零碎知识点形成体系 Iterator 对比 Iterator(迭代器)是一种设计模式,是一个对象,用于遍历集合中的所有元素. Iterator 包含四个方法 ...
- 英语口语练习系列-C09-常用动词
<先秦 · 关雎> 关关雎鸠,在河之洲.窈窕淑女,君子好逑. 参差荇菜,左右流之.窈窕淑女,寤寐求之. 求之不得,寤寐思服.悠哉悠哉,辗转反侧. 参差荇菜,左右采之.窈窕淑女,琴瑟友之. ...
- Linux Mysql 每天定时备份
1.创建脚本 dbback.sh,内容如下: #!/bin/bash mysqldump -uroot -p123456 hexin>/work/db_back/hexin_$(date +%Y ...
- equals方法相关总结
先说一下Object类吧: 这是一个号称为祖宗类的东西,是所有类的父类,也是唯一一个没有父类的类. 接口不继承object类 并且Object类存在于java的lang包中,我们都知道存在于lang包 ...
- 初识shell编程
1.shell编程之为什么学.怎么学 为什么学shell编程 Linux系统批量管理 提升工作效率,减少重复工作 学好shell编程所需要的基础知识 熟悉使用vim编辑器 熟悉SSH终端 熟练掌握Li ...