BZOJ 3110 K大数查询

题面

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c

如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

题解

这道题一个好写的做法是“整体二分”。

我做的上一道整体二分的题目在这里

整体二分的主要过程是:二分答案,然后按照 答案比当前mid小/答案比当前mid大 将询问分为两组,一组放在左边,另一组放在右边,然后递归进行左右两边的二分。

这道题有修改操作,但是也没什么关系,不要被吓住了 =_=

我们的分治策略保证了当前要处理的的询问在时间上是单调的。于是我们从左到右枚举当前要处理的询问,如果是修改操作,则:若修改的c <= mid,则在树状数组上直接进行修改,同时把这个询问放在左边;否则直接放到右边,不修改;如果是查询操作,则看对应区间大于等于当前mid的数的个数(就是树状数组内记录的区间和)是否超过k,决定这个询问应该放在哪一边。

关于树状数组如何记录区间和,请访问我的这篇博客

这道题要注意每次进入分治函数,树状数组都是要清空的,然而我们不能直接memset(会T),于是记录树状数组上每一位是否在本轮更新过(vis数组),如果没更新过,先清零再操作。

下面是我的代码。因为这道题求第k“大”很难受,于是我预处理,把数字重新排序,变成了第k小问题……于是代码长了些。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <complex>
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 50005;
int n, m, times, vis[N], idx, seq[N], buf1[N], buf2[N];
ll ta[N], tb[N], lst[N], ans[N];
struct query{
int type, l, r;
ll k;
} q[N];
void single_add(int p, ll x){
for(int i = p; i <= n; i += i & -i){
if(vis[i] != times)
vis[i] = times, ta[i] = tb[i] = 0;
ta[i] += x, tb[i] += p * x;
}
}
void add(int l, int r, ll x){
single_add(l, x);
single_add(r + 1, -x);
}
ll single_ask(int p){
ll ret = 0;
for(int i = p; i; i -= i & -i)
if(vis[i] == times)
ret += (p + 1) * ta[i] - tb[i];
return ret;
}
ll ask(int l, int r){
return single_ask(r) - single_ask(l - 1);
}
void solve(int ql, int qr, int l, int r){
if(ql > qr) return;
if(l == r){
for(int i = ql; i <= qr; i++)
ans[seq[i]] = lst[l];
return;
}
times++;
int mid = (l + r) >> 1, p1 = 0, p2 = 0;
for(int i = ql; i <= qr; i++){
if(q[seq[i]].type == 1){
if(q[seq[i]].k <= mid){
add(q[seq[i]].l, q[seq[i]].r, 1), buf1[++p1] = seq[i];
}
else buf2[++p2] = seq[i];
}
else{
ll sum = ask(q[seq[i]].l, q[seq[i]].r);
if(sum < q[seq[i]].k) buf2[++p2] = seq[i], q[seq[i]].k -= sum;
else buf1[++p1] = seq[i];
}
}
for(int i = 1; i <= p1; i++) seq[ql + i - 1] = buf1[i];
for(int i = 1; i <= p2; i++) seq[ql + p1 - 1 + i] = buf2[i];
solve(ql, ql + p1 - 1, l, mid);
solve(ql + p1, qr, mid + 1, r);
}
int main(){
read(n), read(m);
for(int i = 1; i <= m; i++){
read(q[i].type), read(q[i].l), read(q[i].r), read(q[i].k);
if(q[i].type == 1) lst[++idx] = q[i].k;
}
sort(lst + 1, lst + idx + 1);
idx = unique(lst + 1, lst + idx + 1) - lst - 1;
for(int i = 1; i <= m; i++)
if(q[i].type == 1)
q[i].k = idx + 1 - (lower_bound(lst + 1, lst + idx + 1, q[i].k) - lst);
for(int i = 1, j = idx; i < j; i++, j--) swap(lst[i], lst[j]);
for(int i = 1; i <= m; i++) seq[i] = i;
solve(1, m, 1, idx);
for(int i = 1; i <= m; i++)
if(q[i].type == 2)
write(ans[i]), enter;
return 0;
}

BZOJ 3110 K大数查询 | 整体二分的更多相关文章

  1. 【BZOJ-3110】K大数查询 整体二分 + 线段树

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Sta ...

  2. [ZJJOI2013]K大数查询 整体二分

    [ZJJOI2013]K大数查询 链接 luogu 思路 整体二分. 代码 #include <bits/stdc++.h> #define ll long long using name ...

  3. BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)

    题目链接 BZOJ 洛谷 整体二分求的是第K小(利用树状数组).求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\). 注意到所有数的绝对值\(\leq N\),将所有数的大小关系 ...

  4. BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

    有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. N ...

  5. BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分

    [题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] ...

  6. P3332 [ZJOI2013]K大数查询 整体二分

    终于入门整体二分了,勉勉强强算是搞懂了一个题目吧. 整体二分很多时候可以比较好的离线处理区间\(K\)大值的相关问题.考虑算法流程: 操作队列\(arr\),其中有询问和修改两类操作. 每次在答案的可 ...

  7. [BZOJ]3110 K大数查询(ZJOI2013)

    这大概是唯一一道小C重写了4次的题目. 姿势不对的树套树(Fail) → 分块(Fail) → 整体二分(Succeed) → 树套树(Succeed). 让小C写点心得静静. Description ...

  8. BZOJ3110:[ZJOI2013]K大数查询(整体二分)

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位 ...

  9. [ZJOI2013]K大数查询——整体二分

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是: 1 a b c:表示在第a个位置到第b个位置,每个位置加上一个数c 2 a b c:表示询问从第a个位置到第b个位置,第C大的数是多少. ...

随机推荐

  1. OpenGL学习笔记(3) 纹理

    关于纹理 一般游戏里的物体不一定都是纯色的物体,物体上面会有一些图片贴在上面,比如墙壁,箱子,地板,可以看到砖头.木板和大理石组成的图片,要把图片贴到计算机里的几何图形的话,就要把图片的颜色采样贴到几 ...

  2. 增强学习训练AI玩游戏

    1.游戏简介 符号A为 AI Agent. 符号@为金币,AI Agent需要尽可能的接取. 符号* 为炸弹,AI Agent需要尽可能的躲避. 游戏下方一组数字含义如下: Bomb hit: 代表目 ...

  3. Flink架构分析之HA

    抽象 LeaderElectionService 这个接口用于从一组竞选者中选出一个leader,其start方法需要传递一个LeaderContender竞选者作为参数,如果有多个竞选者,则每一个竞 ...

  4. could not launch process: decoding dwarf section info at offset 0x0: too short

    Fabric调试异常 作者在使用chaincode进行智能合约开发的过程中,使用Goland + Golang + win10_X64作为开发环境: GoLand 2018.1.4 Build #GO ...

  5. mtr的用法场景

    ---引用自阿里云 mtr (My traceroute)也是几乎所有 Linux 发行版本预装的网络测试工具.他把 ping和 traceroute 的功能并入了同一个工具中,所以功能更强大. mt ...

  6. Swagger本地环境配置

    一.技术背景 随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染.先后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远.而前后端的唯一联系便是 API 接口,与此同 ...

  7. 第十一次ScrumMeeting博客

    第十一次ScrumMeeting博客 本次会议于11月29日(三)22时整在3公寓725房间召开,持续30分钟. 与会人员:刘畅.辛德泰张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的内容和 ...

  8. 机器学习:数据预处理之独热编码(One-Hot)

    前言 ———————————————————————————————————————— 在机器学习算法中,我们经常会遇到分类特征,例如:人的性别有男女,祖国有中国,美国,法国等.这些特征值并不是连续的 ...

  9. Bing词典vs有道词典比对测试报告——体验篇之软件适应性

    联网情况: 在联网情况下,针对每一次查询,有道词典的反应速度明显比必应词典快得多.据我推测有以下两个原因: 有道词典有本地词库而必应词典更多依赖联网. 有道词典的服务器在国内而必应的在国外. 断网情况 ...

  10. oo第八次作业--5,6,7次作业总结

    一.多线程的设计 这三次作业的主要内容就是使用多线程并且解决多线程中出现的问题.而对于多线程我也有了自己的理解.首先明确的一点是单个CPU在同一时间只能处理一件事.那么,不管是多进程还是多线程,我们的 ...