题目描述

给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。

输入

第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。

输出

对于每组询问输出第K小的数。

样例输入

2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3

样例输出

1
3


题解

整体二分+二维树状数组

题目答案具有很明显的二分性质,所以可以考虑把询问离线,整体二分。(其实是看了题解才知道是整体二分的,一开始想了权值线段树套线段树套线段树)

整体二分是什么?和标准的二分几乎是一样的,只不过在判定的时候是把所有答案属于这个区间的询问都一一判定,根据是否满足条件,把询问分成答案属于[l,mid]和[mid+1,r]中的,然后对这两个子区间分别处理。最后当l=r时说明所有属于这个区间内的询问的答案都是l。

那么对于本题,我们可以按照矩阵内的数从大到小排序。然后把所有询问读进来,整体二分。

用solve(b,e,l,r)表示要解决询问区间在[b,e]内,点区间在[l,r]内的答案,那么当l=r时,ans[b~e]=v[l]。

当l≠r时,令mid=(l+r)/2。此时需要判定的就是是否有大于等于k个数在[l,mid]之间。

所以把[l,mid]内对应位置的权值+1,要求的就是矩形内的权值之和,可以使用二维树状数组来解决。

如果矩形内的数的个数大于等于k,则答案在[l,mid]内,把它放到对应的区间中;否则答案在[mid+1,r]中,并且把k值减去数的个数(因为这些数一定是前k小的)。

最后把二维树状数组清空(不能使用memset,需要动态清零),然后递归处理左右区间即可。

时间复杂度$O(q\log^3n)$

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct POINT
{
int x , y , v;
bool operator<(const POINT a)const {return v < a.v;}
}a[250010];
struct QUERY
{
int x1 , y1 , x2 , y2 , k , id;
}q[60010] , t[60010];
int f[510][510] , n , ans[60010];
void add(int x , int y , int a)
{
int i , j;
for(i = x ; i <= n ; i += i & -i)
for(j = y ; j <= n ; j += j & -j)
f[i][j] += a;
}
int query(int x , int y)
{
int i , j , ans = 0;
for(i = x ; i ; i -= i & -i)
for(j = y ; j ; j -= j & -j)
ans += f[i][j];
return ans;
}
void solve(int b , int e , int l , int r)
{
if(b > e) return;
int mid = (l + r) >> 1 , i , tl = b , tr = e , c;
if(l == r)
{
for(i = b ; i <= e ; i ++ ) ans[q[i].id] = a[l].v;
return;
}
for(i = l ; i <= mid ; i ++ ) add(a[i].x , a[i].y , 1);
for(i = b ; i <= e ; i ++ )
{
c = query(q[i].x2 , q[i].y2) - query(q[i].x1 - 1 , q[i].y2) - query(q[i].x2 , q[i].y1 - 1) + query(q[i].x1 - 1 , q[i].y1 - 1);
if(c >= q[i].k) t[tl ++ ] = q[i];
else q[i].k -= c , t[tr -- ] = q[i];
}
for(i = b ; i <= e ; i ++ ) q[i] = t[i];
for(i = l ; i <= mid ; i ++ ) add(a[i].x , a[i].y , -1);
solve(b , tr , l , mid) , solve(tl , e , mid + 1 , r);
}
int main()
{
int m , i , j;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= n ; j ++ )
scanf("%d" , &a[(i - 1) * n + j].v) , a[(i - 1) * n + j].x = i , a[(i - 1) * n + j].y = j;
sort(a + 1 , a + n * n + 1);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d%d%d" , &q[i].x1 , &q[i].y1 , &q[i].x2 , &q[i].y2 , &q[i].k) , q[i].id = i;
solve(1 , m , 1 , n * n);
for(i = 1 ; i <= m ; i ++ ) printf("%d\n" , ans[i]);
return 0;
}

【bzoj2738】矩阵乘法 整体二分+二维树状数组的更多相关文章

  1. BZOJ2738矩阵乘法——整体二分+二维树状数组

    题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入   第一行两个数N,Q,表示矩阵大小和询问组数:接下来N行N列一共N*N个数,表示这个矩阵:再接下来Q行每行5 ...

  2. [BZOJ2738]矩阵乘法 整体二分+二维树状数组

    2738: 矩阵乘法 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1643  Solved: 715[Submit][Status][Discuss ...

  3. BZOJ.2738.矩阵乘法(整体二分 二维树状数组)

    题目链接 BZOJ 洛谷 整体二分.把求序列第K小的树状数组改成二维树状数组就行了. 初始答案区间有点大,离散化一下. 因为这题是一开始给点,之后询问,so可以先处理该区间值在l~mid的修改,再处理 ...

  4. [BZOJ2738]矩阵乘法(整体二分+二维树状数组)

    整体二分+二维树状数组. 好题啊!写了一个来小时. 一看这道题,主席树不会搞,只能用离线的做法了. 整体二分真是个好东西,啥都可以搞,尤其是区间第 \(k\) 大这种东西. 我们二分答案,然后用二维树 ...

  5. BZOJ 2738 矩阵乘法(整体二分+二维树状数组)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2738 [题目大意] 给出一个方格图,询问要求求出矩阵内第k小的元素 [题解] 我们对答 ...

  6. 【清澄A1333】【整体二分+二维树状数组】矩阵乘法(梁盾)

    试题来源 2012中国国家集训队命题答辩 问题描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入格式 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共 ...

  7. 洛谷1527(bzoj2738)矩阵乘法——二维树状数组+整体二分

    题目:https://www.luogu.org/problemnew/show/P1527 不难想到(?)可以用二维树状数组.但维护什么?怎么查询是难点. 因为求第k小,可以考虑记权值树状数组,把比 ...

  8. 洛谷P1527 [国家集训队] 矩阵乘法 [整体二分,二维树状数组]

    题目传送门 矩阵乘法 题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入输出格式 输入格式: 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共N* ...

  9. 洛谷P1527 矩阵乘法——二维树状数组+整体二分

    题目:https://www.luogu.org/problemnew/show/P1527 整体二分,先把所有询问都存下来: 然后二分一个值,小于它的加到二维树状数组的前缀和里,判断一遍所有询问,就 ...

随机推荐

  1. BZOJ3932(主席树上二分+差分

    按时间作为主席树的版本,每个版本的主席树都是一个权值线段树. 差分消去时间影响 对于当前时间版本的主席树查询前K大即可. 树上二分时结束后切记判定l==r的状态(易错 l==r叶子节点可能存在多个值( ...

  2. RHEL7 本地yum源配置

    配置yum 源 1.挂载DVD光盘到/mnt   因为配置时候路径名里面不能有空格,否则不能识别  [root@ mnt]# mount /dev/cdrom /mnt 2.在目录/etc/yum.r ...

  3. 【BZOJ2427】[HAOI2010] 软件安装(缩点+树形DP)

    点此看题面 大致题意: 有\(N\)个软件,每个软件有至多一个依赖以及一个所占空间大小\(W_i\),只有当一个软件的直接依赖和所有的间接依赖都安装了,它才能正常工作并造成\(V_i\)的价值.求在容 ...

  4. vuejs组件的重要选项

    new Vue({ el:'#demo', data:{ message:'Hello vue.js!' } }) 我们看到这个括号里面包含了很多中间的选项,小括号里面其实是一些参数,这些参数指定了实 ...

  5. Dynemic Web Project中使用servlet的 doGet()方法接收来自浏览器客户端发送的add学生信息形成json字符串输出到浏览器并保存到本地磁盘文件

    package com.swift.servlet; import java.io.FileOutputStream;import java.io.IOException;import java.io ...

  6. utf8、ansii、unicode编码之间的转换

    #include "stdafx.h"#include "windows.h"#include <iostream>#include <str ...

  7. git与github账号建立SSH连接

    第1步:创建SSH Key.在用户主目录下,(就是在你的工作空间一层)看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步 ...

  8. Mybatis 插入一条或批量插入 返回带有自增长主键记录

    首先讲一下,  插入一条记录返回主键的 Mybatis 版本要求低点,而批量插入返回带主键的 需要升级到3.3.1版本,3.3.0之前的都不行, <dependency> <grou ...

  9. 7- vue django restful framework 打造生鲜超市 -商品类别数据展示(上)

    Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页 并没有将列表页的数据json 与前端的页面展示结合起来 讲解如果将dr ...

  10. HashMap 排序

    本文章,摘抄自:2018黑马程序最新面试题汇总 已知一个 HashMap<Integer,User>集合, User 有 name(String)和 age(int)属性.请写一个方法实现 ...