P2617 Dynamic Rankings 解题报告
整体二分是一种东西,比如上面这道题。
先考虑一个不带修版本的,也就是经典问题区间 kth,显然我们可以主席树但是我知道你很想用主席树但是你先别用不用主席树,用一种离线的算法,叫整体二分。
首先先考虑处理单个询问,二分,简单吗?真简单,先二分一个 \(mid\),然后把区间内所有小于等于 \(mid\) 的数字丢进一个权值树状数组里,统计一下这些数字有多少个,就可以判定了。那么这个时候时间复杂度应该是 \(O((r - l + 1) \log_2 SIZE^2)\) 的(权值树状数组与二分带两只 log)。离散化就可以做到 \(O((r - l + 1)\log_2 (r - l + 1)^2)\),但一般没必要这么做(懒捏┓( ´∀` )┏)
我们学会了对一个询问这么做,那么多个询问呢?不难想到我们可以先二分一个 \(mid\),然后对于答案小于等于 \(mid\) 的询问,丢到一块,对于答案大于 \(mid\) 的询问也丢到一块。然后两块分别递归处理。
然后你就会发现你被骗了其实这样做是不行的,因为如果我们只把询问丢到一块,那么我们怎么更新元素呢?我们一个一个一个一个的扫描长度为 \(n\) 的数组 \(a\),然后将 \(a[i]\le mid\) 的元素丢到左半边,\(a[i]>mid\) 的丢到右半边?没必要啊!我们完全可以把初始序列看成 \(n\) 次对 \(i\) 位置添加一个权值为 \(a[i]\) 的操作。然后你就会发现,我们也应该一并把 \(a[i]\le mid\) 的添加操作丢到左半边,\(a[i] > mid\) 操作丢到右半边。
由于我语文太烂了,所以看不懂上面的很正常 QAQ简单来说,整体二分就是每次二分一个 \(mid\),然后将答案小于等于 \(mid\) 与会让答案小于等于 \(mid\) 的操作一块丢到左边,答案大于 \(mid\) 的查询和会让答案大于 \(mid\) 的操作丢到右边。这样就好啦(*^▽^*)。
这就是伟大的整体二分算法,是不是相当简单?总的来说,就是每次二分一个值,普通的二分是,如果只有一个询问,我们就把它划分,然后继续二分。整体二分,就是每次二分出来一个值,然后都得对一串进行划分。
这个东西出现在了 2013 年国家集训队论文里面,是许昊然这个巨佬讲的,所以建议直接看这篇文章反正他写的比我这个大蒟蒻写的好 1145141919810 倍我写这个就是给自己看的我有的时候都看不懂自己在写什么,比如语文考试的作文 QAQ。这篇文章里,谈到了整体二分的 5 个应用前提:
- 询问的答案具有可二分性。
- 修改对判定答案的贡献互相独立,修改之间互不影响效果
- 修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值
- 贡献满足交换律、结合律,具有可加性
- 题目允许离线算法
以上出自许昊然巨佬论文的原文。第一点显而易见,不然你怎么整体二分。第五点也很显然,因为整体二分就是把所有操作放在一块处理,不能离线怎么放在一块。第二点为什么要“互相独立”呢?假设你的修改是“修改了 p 后才能修改 q”或者“修改了 p 就不能修改 q”这个时候就很不可做。大部分 DS 题都是修改之间互不影响效果的吧 qwq。第三点也很简单,就是说我们修改了后,判定还是照样的判定方法。拿上面这题举例子,刚开始的加数我们看成修改,显而易见,修改是修改了,但是我们判定就是小于等于 \(mid\),是不会有影响的。第四点也不难理解,拿上面那题举例子,每个点的贡献就是如果这个点小于等于 \(mid\),就会贡献一个 \(1\),满足交换律,结合律(你先更新哪个点后更新哪个点都一样),同时显而易见具有可加性。
回到动态区间 kth 来,不难发现,为了独立每个修改的贡献,我们完全可以把单点修改拆成“删除原来的值”和“加入更新的值”,如此一来这样贡献就能独立了。
删除原来的值和上面讨论过的“加入更新的值”就反着来就好了吧,还是很简单的说 awa
#include <iostream>
#include <cstring>
#define MAXN 200000
using namespace std;
int tr[MAXN + 10], n, m, tot;
int lowbit(int x) {return (x & (-x));}
void add(int pos, int val) {
for(; pos <= n; pos += lowbit(pos))
tr[pos] += val;
}
int query(int pos) {
int rest = 0;
while(pos) {
rest += tr[pos];
pos -= lowbit(pos);
}
return rest;
}
//type = 0 query
//type = 1 insert
//type = 2 delete
struct node {
int type, val, l, r, ind;
//For type = 0
//[l, r] val ind = i
//For type = 1/2
// l val ind = i
} Q[MAXN * 2 + 10], qa[MAXN * 2 + 10], qb[MAXN * 2 + 10];
int ans[MAXN + 10], a[MAXN + 10];
void twofen(int l, int r, int s, int t) {
if(l > r) return ;
if(s == t) {
for(int p = l; p <= r; p++)
if(!Q[p].type)
ans[Q[p].ind] = s;
return ;
}
int mid = (s + t) >> 1, ta = 0, tb = 0;
for(int p = l; p <= r; p++) {
if(Q[p].type == 0) {
int qr = query(Q[p].r) - query(Q[p].l - 1);
if(qr >= Q[p].val) qa[++ta] = Q[p];
else Q[p].val -= qr, qb[++tb] = Q[p];
}
else if(Q[p].type == 1) {
if(Q[p].val <= mid) add(Q[p].l, 1), qa[++ta] = Q[p];
else qb[++tb] = Q[p];
}
else if(Q[p].type == 2) {
if(Q[p].val <= mid) add(Q[p].l, -1), qa[++ta] = Q[p];
else qb[++tb] = Q[p];
}
}
for(int p = l; p <= r; p++)
if(Q[p].val <= mid)
if(Q[p].type == 1) add(Q[p].l, -1);
else if(Q[p].type == 2) add(Q[p].l, 1);
for(int p = l, i = 1; i <= ta; p++, i++) Q[p] = qa[i];
for(int p = l + ta, i = 1; i <= tb; p++, i++) Q[p] = qb[i];
twofen(l, l + ta - 1, s, mid);
twofen(l + ta, r, mid + 1, t);
}
int main() {
freopen("read.txt", "r", stdin);
freopen("write.txt", "w", stdout);
cin >> n >> m;
for(int p = 1; p <= n; p++) {
tot++;
cin >> a[p], Q[tot].val = a[p];
Q[tot].type = 1, Q[tot].l = p;
}
char opt;
int qt = 0;
for(int p = 1; p <= m; p++) {
cin >> opt;
if(opt == 'Q') {
tot++;
cin >> Q[tot].l >> Q[tot].r >> Q[tot].val;
Q[tot].ind = ++qt, Q[tot].type = 0;
}
else {
int rt, rest; tot++;
cin >> rt >> rest;
Q[tot].l = rt;
Q[tot].val = a[rt];//这里一直写成 a[p] 调了好久,太菜了 QAQ
Q[tot].type = 2;
tot++;
Q[tot].l = rt, Q[tot].val = rest;
Q[tot].type = 1, a[rt] = rest;
}
}
twofen(1, tot, 0, 1e9);
for(int p = 1; p <= qt; p++)
cout << ans[p] << endl;
}
P2617 Dynamic Rankings 解题报告的更多相关文章
- 洛谷 P2617 Dynamic Rankings 解题报告
P2617 Dynamic Rankings 题目描述 给定一个含有\(n\)个数的序列\(a[1],a[2],a[3],\dots,a[n]\),程序必须回答这样的询问:对于给定的\(i,j,k\) ...
- P2617 Dynamic Rankings(树状数组套主席树)
P2617 Dynamic Rankings 单点修改,区间查询第k大 当然是无脑树套树了~ 树状数组套主席树就好辣 #include<iostream> #include<cstd ...
- 2018.07.01洛谷P2617 Dynamic Rankings(带修主席树)
P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i ...
- 洛谷P2617 Dynamic Rankings (主席树)
洛谷P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a ...
- 【学习笔鸡】整体二分(P2617 Dynamic Rankings)
[学习笔鸡]整体二分(P2617 Dynamic Rankings) 可以解决一些需要树套树才能解决的问题,但要求询问可以离线. 首先要找到一个具有可二分性的东西,比如区间\(k\)大,就很具有二分性 ...
- 洛谷$P2617\ Dynamic\ Rankings$ 整体二分
正解:整体二分 解题报告: 传送门$w$ 阿查询带修区间第$k$小不显然整体二分板子呗,,, 就考虑先按时间戳排序(,,,其实并不需要读入的时候就按着时间戳排的鸭$QwQ$ 每次二分出$mid$先把所 ...
- P2617 Dynamic Rankings(待修改区间第k大)
题目链接:https://www.luogu.org/problemnew/show/P2617 题目: 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的 ...
- luogu P2617 Dynamic Rankings && bzoj 1901 (带修改区间第k大)
链接:https://www.luogu.org/problemnew/show/P2617 思路: 如果直接在主席树上修改的话,每次修改都会对后面所有的树造成影响,一次修改的复杂度就会变成 : n* ...
- SP8791 DYNALCA - Dynamic LCA 解题报告
SP8791 DYNALCA - Dynamic LCA 有一个森林最初由 \(n (1 \le n \le 100000)\) 个互不相连的点构成 你需要处理以下操作: link A B:添加从顶点 ...
- LUOGU P2617 Dynamic Rankings(树状数组套主席树)
传送门 解题思路 动态区间第\(k\)大,树状数组套主席树模板.树状数组的每个位置的意思的是每棵主席树的根,维护的是一个前缀和.然后询问的时候\(log\)个点一起做前缀和,一起移动.时空复杂度\(O ...
随机推荐
- Selenium4+Python3系列(十) - Page Object设计模式
前言 Page Object(PO)模式,是Selenium实战中最为流行,并且被自动化测试同学所熟悉和推崇的一种设计模式之一.在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一定的 ...
- fiddler提示"The system proxy was changed,click to reenable fiddler capture"的解决方法
之前用fiddler 一直都是正常的,但是过了几个月再次使用的时候没几秒钟就提示:The system proxy was changed,click to reenable fiddler capt ...
- Excel二维码图片生成器
Excel二维码图片生成器 它可以将excel文件的数据,每行数据生成一张二维码图片,并保存到电脑.软件无需安装,解压后即可直接使用,无需联网,操作简便快捷. 软件下载地址:点此下载 步骤1:导入事先 ...
- ffmpeg库安装及入门指南(Windows篇)- 2022年底钜献
最近项目需要,使用了 ffmpeg 做摄像头视频采集和串流.这几天有点时间,打算把相关的一些知识记录分享一下. 在撰写本文时,我又在另外一台电脑上把 ffmpeg 重新安装了一遍,所以绝对真实靠谱!如 ...
- ORM常用字段与参数(自定义字段)
目录 一:orm中常用字段及参数 1.说明 2.自定义字段使用 3.ORM字段参数 一:orm中常用字段及参数 1.说明 id字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定pri ...
- 侦察工具——Httrack
前言 web渗透学习笔记,实验环境为Metasploitable靶机上的DVWA.此随笔介绍Web渗透侦察工具Httrack Httrack 简介 Httrack能够克隆拷贝目标网站上的所有可访问.可 ...
- kali安装拼音输入法
前言 最近使用kali感觉没个中文输入法的很不方便,于是决定装个ibus的拼音输入法 安装方法 1.安装ibus 使用命令apt install ibus ibus-pinyin,注意使用root权限 ...
- JavaScript:箭头函数:作为参数进行传参
之前已经说过,JS的函数,也是对象,而函数名是一个变量,是可以进行传参的,也即函数是可以被传参的. 只要是函数,都可以被传参,但是箭头函数的语法更为灵活,所以更方便进行传参. 如上图所示,fun1是一 ...
- 第一百一十七篇: JavaScript 工厂模式和原型模式
好家伙,本篇为<JS高级程序设计>第八章"对象.类与面向对象编程"学习笔记 1.工厂模式 工厂模式是另外一种关注对象创建概念的创建模式. 它的领域中同其它模式的不同 ...
- 就聊聊不少小IT公司的技术总监
本文想告诉大家如下两个观点. 1 很多IT小公司的技术总监,论能力其实也就是相当于大公司的高级程序员. 2 程序员在职业发展过程中,绝对应该优先考虑进大厂或好公司.如果仅仅停留在小公司,由于小公司可能 ...