BZOJ 2738 子矩阵第k大 | 二维树状数组 整体二分 分治
BZOJ 2738 “矩阵乘法”(子矩阵第k大)
题意
给出一个矩阵,多次询问子矩阵中第k大的数是多少。
题解
我做这道题之前先照着这道题出了一道题,是这道题的一维版本,在这里:https://vijos.org/d/contest/p/5a26541bd3d8a11cef1706aa。
思路是这样的:二分答案mid,将所有小于mid的位置都在树状数组上 +1,对于每个询问,如果子矩阵所有”+1“之和 >= 这个询问的k,则把询问划分到”左边那一组”,否则划分到“右边那一组”,之后对它们分别处理。
核心代码:
void solve(int l, int r, int ql, int qr){
if(ql > qr) return;
if(l == r){
for(int i = ql; i <= qr; i++)
ans[q[i].id] = a[l].val;
return;
}
int mid = (l + r) >> 1, cnt = 0;
for(int i = l; i <= mid; i++)
add(a[i].x, a[i].y, 1);
for(int i = ql; i <= qr; i++){
sum[i] = ask(q[i]);
if(sum[i] >= q[i].k) cnt++;
}
for(int i = ql, pl = ql, pr = ql + cnt; i <= qr; i++)
if(sum[i] >= q[i].k) tmp[pl++] = q[i];
else q[i].k -= sum[i], tmp[pr++] = q[i];
for(int i = ql; i <= qr; i++) q[i] = tmp[i];
for(int i = l; i <= mid; i++)
add(a[i].x, a[i].y, -1);
solve(l, mid, ql, ql + cnt - 1);
solve(mid + 1, r, ql + cnt, qr);
}
完整代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#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 = 505, M = 60005;
int n, m, tr[N][N], ans[M], idx, sum[M];
struct element {
int x, y, val;
bool operator < (const element &b) const{
return val < b.val;
}
} a[N*N];
struct query {
int id, xa, ya, xb, yb, k;
} q[M], tmp[M];
void add(int x, int y, int val){
for(int px = x; px <= n; px += px & -px)
for(int py = y; py <= n; py += py & -py)
tr[px][py] += val;
}
int single_ask(int x, int y){
int ret = 0;
for(int px = x; px; px -= px & -px)
for(int py = y; py; py -= py & -py)
ret += tr[px][py];
return ret;
}
int ask(query Q){
return single_ask(Q.xb, Q.yb) - single_ask(Q.xa - 1, Q.yb) - single_ask(Q.xb, Q.ya - 1) + single_ask(Q.xa - 1, Q.ya - 1);
}
void solve(int l, int r, int ql, int qr){
if(ql > qr) return;
if(l == r){
for(int i = ql; i <= qr; i++)
ans[q[i].id] = a[l].val;
return;
}
int mid = (l + r) >> 1, cnt = 0;
for(int i = l; i <= mid; i++)
add(a[i].x, a[i].y, 1);
for(int i = ql; i <= qr; i++){
sum[i] = ask(q[i]);
if(sum[i] >= q[i].k) cnt++;
}
for(int i = ql, pl = ql, pr = ql + cnt; i <= qr; i++)
if(sum[i] >= q[i].k) tmp[pl++] = q[i];
else q[i].k -= sum[i], tmp[pr++] = q[i];
for(int i = ql; i <= qr; i++) q[i] = tmp[i];
for(int i = l; i <= mid; i++)
add(a[i].x, a[i].y, -1);
solve(l, mid, ql, ql + cnt - 1);
solve(mid + 1, r, ql + cnt, qr);
}
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
a[++idx].x = i, a[idx].y = j, read(a[idx].val);
sort(a + 1, a + idx + 1);
for(int i = 1; i <= m; i++)
q[i].id = i, read(q[i].xa), read(q[i].ya), read(q[i].xb), read(q[i].yb), read(q[i].k);
solve(1, idx, 1, m);
for(int i = 1; i <= m; i++)
write(ans[i]), enter;
return 0;
}
BZOJ 2738 子矩阵第k大 | 二维树状数组 整体二分 分治的更多相关文章
- 洛谷1527(bzoj2738)矩阵乘法——二维树状数组+整体二分
题目:https://www.luogu.org/problemnew/show/P1527 不难想到(?)可以用二维树状数组.但维护什么?怎么查询是难点. 因为求第k小,可以考虑记权值树状数组,把比 ...
- 洛谷P1527 矩阵乘法——二维树状数组+整体二分
题目:https://www.luogu.org/problemnew/show/P1527 整体二分,先把所有询问都存下来: 然后二分一个值,小于它的加到二维树状数组的前缀和里,判断一遍所有询问,就 ...
- BZOJ 1452 Count 【模板】二维树状数组
对每种颜色开一个二维树状数组 #include<cstdio> #include<algorithm> using namespace std; ; ][maxn][maxn] ...
- 【 HDU - 4456 】Crowd (二维树状数组、cdq分治)
BUPT2017 wintertraining(15) #5A HDU 4456 题意 给你一个n行n列的格子,一开始每个格子值都是0.有M个操作,p=1为第一种操作,给格子(x,y)增加z.p=2为 ...
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
3110 [Zjoi2013]K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a ...
- BZOJ 1452:[JSOI2009]Count(二维树状数组)
[JSOI2009]Count 描述 输入 输出 1 2 分析: 裸二维bit,对每个颜色建一颗bit. program count; var bit:..,..,..]of longint; a:. ...
- POJ 1195:Mobile phones 二维树状数组
Mobile phones Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 16893 Accepted: 7789 De ...
- BZOJ.2738.矩阵乘法(整体二分 二维树状数组)
题目链接 BZOJ 洛谷 整体二分.把求序列第K小的树状数组改成二维树状数组就行了. 初始答案区间有点大,离散化一下. 因为这题是一开始给点,之后询问,so可以先处理该区间值在l~mid的修改,再处理 ...
- BZOJ 2738 矩阵乘法(整体二分+二维树状数组)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2738 [题目大意] 给出一个方格图,询问要求求出矩阵内第k小的元素 [题解] 我们对答 ...
随机推荐
- linux 开机报错,error grub_efi_find_mmap_size not find
开机报错,差点以为要重装系统了 搜到了官方的重建引导的教程 修复了错误 https://wiki.manjaro.org/index.php/Restore_the_GRUB_Bootloader#F ...
- 《杜增强讲Unity之Tanks坦克大战》6-发射子弹
6 发射子弹 本节完成发射子弹的功能,最终代码如下: image 首先,发射子弹得确定发射的位置和方向,还有发射的初始速度.具体的发射速度和按下发射按键的时间长短有关,这个关于子弹的蓄力我们在第九 ...
- Unity3D — — UGUI之RectTransform
Mask.GetComponent<RectTransform>().anchoredPosition(子物体) = hotKey_image.rectTransform.anchored ...
- Linux速成(二)
四.Linux 系统目录结构 树状目录结构: 以下是对这些目录的解释: /bin:bin是Binary的缩写, 这个目录存放着最经常使用的命令. /boot:这里存放的是启动Linux时使用的一些核心 ...
- 微信小程序-帝国cms会员系统调用
在用户->管理会员字段,增加如下字段:openidsession_keylsktokennicknameheadimg设置用户名长度然后,在系统,系统变最设置,用户设置,将注册用户名设置长度改成 ...
- 国密算法--Openssl 实现国密算法(基础介绍和产生秘钥对)
国密非对称加密算法 又称sm2,它是采取了ECC(曲线加密算法)中的一条固定的曲线,实际上就是ECC算法. 因为openssl里面不包含sm2算法,所以就要重新进行封装-. - 对于ECC算法我就不介 ...
- python - 定时清理ES 索引
只保留三天 #!/usr/bin/env python3 # -*- coding:utf-8 -*- import os import datetime # 时间转化为字符串 now_time = ...
- mongodb基本使用(三)
MongoDB 创建数据库 语法 MongoDB 创建数据库的语法格式如下: use DATABASE_NAME 如果数据库不存在,则创建数据库,否则切换到指定数据库. 如果你想查看所有数据库,可以使 ...
- Spring的Controller映射规则
URL映射 1) 一般格式@RequestMapping(value=“/test”) 2) 可以使用模板模式映射,@RequestMapping(value=“/test/{userId}”) 3) ...
- 团队作业8——测试与发布(Beta阶段)之展示博客
展示博客 1. 团队成员的简介和个人博客地址,团队的源码仓库地址. a.陈福鹏 擅长技术:java.web等网站方面技术: 博客:http://www.cnblogs.com/royalchen/b. ...