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

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2738

【题目大意】

  给出一个方格图,询问要求求出矩阵内第k小的元素

【题解】

  我们对答案的大小进行整体二分,用二维树状数组维护二维区间和,
  将超过数量的分治到左区间,不满足的分治到右区间即可。

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=250010,M=510;
namespace Td_BIT{
    int c[M][M];
    void Initialize(){memset(c,0,sizeof(c));}
    void add(int x,int y,int val){
        for(int i=x;i<M;i+=i&-i)
            for(int j=y;j<M;j+=j&-j)c[i][j]+=val;
    }
    int query(int x,int y){
        int res=0;
        for(int i=x;i;i-=i&-i)
            for(int j=y;j;j-=j&-j)res+=c[i][j];
        return res;
    }
}
struct Q{int x1,x2,y1,y2,k;}q[N];
struct data{int x,y,val;}a[N];
bool operator<(data a,data b){return a.val<b.val;}
int cnt;
int query(int k){
    using namespace Td_BIT;
    int x1=q[k].x1,y1=q[k].y1,x2=q[k].x2,y2=q[k].y2;
    return query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1);
}
int mark[N],ans[N],id[N],tmp[N],T=0;
void solve(int l,int r,int L,int R){
    if(l>r||L==R)return;
    int mid=(L+R)>>1;
    while(a[T+1].val<=mid&&T<cnt){Td_BIT::add(a[T+1].x,a[T+1].y,1);T++;}
    while(a[T].val>mid){Td_BIT::add(a[T].x,a[T].y,-1);T--;}
    int cnt=0;
    for(int i=l;i<=r;i++){
        if(query(id[i])>q[id[i]].k-1){
            mark[i]=1;
            ans[id[i]]=mid;
            cnt++;
        }else mark[i]=0;
    }int l1=l,l2=l+cnt;
    for(int i=l;i<=r;i++){
        if(mark[i])tmp[l1++]=id[i];
        else tmp[l2++]=id[i];
    }for(int i=l;i<=r;i++)id[i]=tmp[i];
    solve(l,l1-1,L,mid);solve(l1,l2-1,mid+1,R);
}
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    int mx=cnt=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            a[++cnt].x=i; a[cnt].y=j;
            scanf("%d",&a[cnt].val);
            mx=max(a[cnt].val,mx);
        }
    }sort(a+1,a+cnt+1);
    for(int 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);
    for(int i=1;i<=m;i++)id[i]=i;
    solve(1,m,0,mx+1);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}
时间: 2024-08-26 15:27:27

BZOJ 2738 矩阵乘法(整体二分+二维树状数组)的相关文章

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

题目大意:给定一个矩阵,多次求某个子矩阵中的第k小 分块解法见 http://blog.csdn.net/popoqqq/article/details/41356899 <论除最小割外题目解法从来与题目名称无关系列> 整体二分 Solve(x,y,S)表示处理答案在[x,y]区间内的询问集合S 预先将所有数按照大小排序 每次将[1,mid]之间的数插入树状数组 然后对于分治内部的每一个询问 去树状数组中查询相应子矩阵的数值 如果小于等于k就划分到左集合S1 否则划分到右集合S2 然后Solv

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

试题来源 2012中国国家集训队命题答辩 问题描述 给你一个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

USACO5.3 IDDFS_强连通_二维树状数组_斐蜀定理_矩形切割

启发式搜索 启发式搜索的主要思想是通过评价一个状态有"多好"来改进对于解的搜索. 方法#1:启发式剪枝 估价函数最简单最普通的用法是进行剪枝.假设有一个求最小代价的一个搜索,使用一个可行的估价函数.如果搜到当前状态时代价为A,这个状态的估价函数是B,那么从这个状态开始搜所能得到的最小代价是A+B.如果当前最优解是C满足C 方法#2:最佳优先搜索 最佳搜索可以看成贪心的深度优先搜索. 与一般搜索随意扩展后继节点不同,最优优先搜索按照估价函数所给的他们的"好坏"的顺序扩

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

poj 1195:Mobile phones(二维树状数组,矩阵求和)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

BZOJ 1452 JSOI 2009 Count 二维树状数组

题目大意:有一个m*n的方格,每一个格子有他自己的权值.2种操作: 1.改变一个格子的权值. 2.查询所有的x1 <= x <= x2 && y1 <= y <= y2的中,有多少个格子颜色是c. 思路:好像是二维树状数组的样子,但是不知道怎么搞.后来研究了数据范围,发现格子最大300*300,颜色最多才100种,于是算一下300*300*100*4/1024/1024大概是35M,题目要求64M,可以搞了.(这里算的精确一点,我当时没怎么算,吧颜色开成300的了,

BZOJ 1452: [JSOI2009]Count 二维树状数组

1452: [JSOI2009]Count Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1452 Description Input Output Sample Input Sample Output 1 2 HINT 题意 题解: 裸的二维树状数组 代码: //qscqesze #include <cstdio> #include <cmath&g

BZOJ 2244 SDOI2011 拦截导弹 CDQ分治/二维树状数组

题目大意:给定一个序列,每个元素是一个二元组,等概率选择一LIS,求LIS长度以及每个元素被选中的概率 第一问CDQ分治裸上 第二问用每个元素所在的LIS个数/总LIS个数就是答案 每个元素所在的LIS自己必选,然后统计前面的方案数和后面的方案数 以前面的方案数为例,令f[x]为以x结尾的LIS长度,那么有DP方程: g[i]=Σg[j] (f[j]+1=f[i],j<i,a[j].x<a[i].x,a[j].y<a[i].y) 将所有元素按f值排序,分层DP,每层DP是一个三维偏序,上

BZOJ 3594 [Scoi2014]方伯伯的玉米田(二维树状数组)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3594 [题目大意] 给出一个数列,选出k个区间使得区间内数全部加1, 求k次操作之后最长的不下降子序列 [题解] 我们发现,每次的区间右端点一定贪心选到最右端才是最优的, 那么在用树状数组统计的时候,只要一个点被+1了,那么后面的点起码+1, 我们在树状数组后面加一维统计被区间包含的次数,发现也是前缀和关系, 所以用二维树状数组统计答案即可. 为避免自身被重复统计,第二维循环降序.