link

整体二分是一种东西,比如上面这道题。

先考虑一个不带修版本的,也就是经典问题区间 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 个应用前提:

  1. 询问的答案具有可二分性。
  2. 修改对判定答案的贡献互相独立,修改之间互不影响效果
  3. 修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值
  4. 贡献满足交换律、结合律,具有可加性
  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 解题报告的更多相关文章

  1. 洛谷 P2617 Dynamic Rankings 解题报告

    P2617 Dynamic Rankings 题目描述 给定一个含有\(n\)个数的序列\(a[1],a[2],a[3],\dots,a[n]\),程序必须回答这样的询问:对于给定的\(i,j,k\) ...

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

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

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

  4. 洛谷P2617 Dynamic Rankings (主席树)

    洛谷P2617 Dynamic Rankings 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a ...

  5. 【学习笔鸡】整体二分(P2617 Dynamic Rankings)

    [学习笔鸡]整体二分(P2617 Dynamic Rankings) 可以解决一些需要树套树才能解决的问题,但要求询问可以离线. 首先要找到一个具有可二分性的东西,比如区间\(k\)大,就很具有二分性 ...

  6. 洛谷$P2617\ Dynamic\ Rankings$ 整体二分

    正解:整体二分 解题报告: 传送门$w$ 阿查询带修区间第$k$小不显然整体二分板子呗,,, 就考虑先按时间戳排序(,,,其实并不需要读入的时候就按着时间戳排的鸭$QwQ$ 每次二分出$mid$先把所 ...

  7. P2617 Dynamic Rankings(待修改区间第k大)

    题目链接:https://www.luogu.org/problemnew/show/P2617 题目: 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的 ...

  8. luogu P2617 Dynamic Rankings && bzoj 1901 (带修改区间第k大)

    链接:https://www.luogu.org/problemnew/show/P2617 思路: 如果直接在主席树上修改的话,每次修改都会对后面所有的树造成影响,一次修改的复杂度就会变成 : n* ...

  9. SP8791 DYNALCA - Dynamic LCA 解题报告

    SP8791 DYNALCA - Dynamic LCA 有一个森林最初由 \(n (1 \le n \le 100000)\) 个互不相连的点构成 你需要处理以下操作: link A B:添加从顶点 ...

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

    传送门 解题思路 动态区间第\(k\)大,树状数组套主席树模板.树状数组的每个位置的意思的是每棵主席树的根,维护的是一个前缀和.然后询问的时候\(log\)个点一起做前缀和,一起移动.时空复杂度\(O ...

随机推荐

  1. python字符串常用方法介绍,基于python3.10

    python字符串常用方法-目录: 1.strip().lstrip().rstrip()2.removeprefix().removesuffix()3.replace()4.split().rsp ...

  2. <五>模板的完全特例化和非完全特例化

    模板作为C++泛型编程的基础十分重要,其使得一份代码能用于处理多种数据类型.而有些时候,我们会希望对一些特定的数据类型执行不同的代码,这时就需要使用模板特例化(template specializat ...

  3. instanceof和Class.isAssignableFrom的区别

    1. Class.isAssignableFrom 偶然看见同事写的一段代码是这样的 if( AfterRender.class.isAssignableFrom( assembly.getClass ...

  4. mysql数据库(字段约束条件)

    什么是字段约束 字段约束就是将字段的内容定一个规则,我们要按照规则办事 约束 描述 关键字 非空约束 限制该字段的数据不能为null not null 唯一约束 保证该字段的所有数据都是唯一.不重复的 ...

  5. BUU_RE学习记录

    一.easyre 1.010打开,直接搜flag,得到flag 二.reverse1 1.先查壳,得知是64位无壳,直接用IDA打开 2.shiftF12查找字符串,发现关键语句 3.查看相应代码,F ...

  6. 万万没想到,go的数据库操作,也能像php一样溜了

    Hi,各位go的小伙伴. 很多人都是从php转过来的吧,不知道你们有没有发现,go界的orm并没有像php的orm一样好用.这篇文章里,我们认真的讨论下这个问题,并且会在后面提出解决方案. php的方 ...

  7. CH579(Cortex-M0)网络IAP升级介绍及问题解答--(持续更新) 网络升级

    CH579网络IAP升级的源码可以从码云(Gitee)上git clone下来. 码云地址:https://gitee.com/maji19971221/wch-ch57x 以下是一个朋友问的几个常见 ...

  8. 什么是RPC? (全面了解)

    一:RPC 1.什么是RPC? RPC 是指远程过程调用,也就是说两台服务器,A 和 B,一个应用部署在A 服务器上,想要调用B 服务器上应用提供的函数或方法,由于不在一个内存空间,不能直接调用,需要 ...

  9. 道长的算法笔记:Trie字典树

    Trie模板 Trie 是一种用于实现字典序快速检索的多叉树结构,Trie 每个节点都有若干的字符指针,若在扫扫描字符串时扫到字符 \(c\),则沿着当前节点 \(c\) 字符指针走向该指针指向的节点 ...

  10. [cocos2d-x]关于CC_CALLBACK

    CC_CALLBACK的代码 // new callbacks based on C++11 #define CC_CALLBACK_0(__selector__,__target__, ...) s ...