【清澄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
3

数据规模和约定

  矩阵中数字是109以内的非负整数;
  20%的数据:N<=100,Q<=1000;
  40%的数据:N<=300,Q<=10000;
  60%的数据:N<=400,Q<=30000;
  100%的数据:N<=500,Q<=60000。

【分析】

其实用可持久化的线段树应该也可以做。

裸的整体二分题,把每个输入的点按权值排个序就可以了。

其实可以加一点修改什么的,这样加着修改一起二分难度稍微大一点。

本周在校最后一题,哈哈哈..

  1 /*
  2 李商隐
  3 《无题·重帏深下莫愁堂》
  4 重帏深下莫愁堂,卧后清宵细细长。
  5 神女生涯原是梦,小姑居处本无郎。
  6 风波不信菱枝弱,月露谁教桂叶香。
  7 直道相思了无益,未妨惆怅是清狂。
  8 */
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <algorithm>
 12 #include <cstring>
 13 #include <vector>
 14 #include <utility>
 15 #include <iomanip>
 16 #include <string>
 17 #include <cmath>
 18 #include <queue>
 19 #include <assert.h>
 20 #include <map>
 21 #include <ctime>
 22 #include <cstdlib>
 23 #include <stack>
 24 #define LOCAL
 25 const int MAXN = 500 + 10;
 26 const int MAXM = 60000 + 10;
 27 const int INF = 1000000000;
 28 const int SIZE = 450;
 29 const int maxnode =  250005 + 10;
 30 using namespace std;
 31 typedef long long ll;
 32 using namespace std;
 33 int n, m, cnt;
 34 int pos, Maxv;
 35 int c[MAXN][MAXN], Ans[MAXM];
 36 int id[MAXM];
 37 int tmp[MAXM];
 38 bool mark[MAXM];
 39
 40 struct DATA{
 41     //横纵坐标和值
 42     int x, y, val;
 43     bool operator < (const DATA &b)const {
 44          return val < b.val;
 45     }
 46 }data[maxnode];
 47 //问题
 48 struct QUESTION{
 49     int x1, x2;
 50     int y1, y2, K;
 51 }q[MAXM];
 52 //输入
 53
 54 inline int lowbit(int x){return x & -x;}
 55 //插入
 56 void add(int x, int y, int val){
 57     int f = y;
 58     while (x <= n){
 59           while (y <= n){
 60                 c[x][y] += val;
 61                 y += lowbit(y);
 62           }
 63           y = f;
 64           x += lowbit(x);
 65     }
 66     return;
 67 }
 68 int sum(int x, int y){//和
 69     int tmp = 0, f = y;
 70     while (x > 0){
 71           while (y > 0){
 72                 tmp += c[x][y];
 73                 y -= lowbit(y);
 74           }
 75           y = f;
 76           x -= lowbit(x);
 77     }
 78     return tmp;
 79 }
 80 //查询
 81 int query(int k){
 82     int x1, x2, y1, y2;
 83     x1 = q[k].x1;x2 = q[k].x2;
 84     y1 = q[k].y1;y2 = q[k].y2;
 85     return sum(x2, y2) + sum(x1 - 1, y1 - 1) - sum(x1 - 1, y2) - sum(x2, y1 - 1);
 86 }
 87 //整体二分
 88 void solve(int l, int r, int L, int R){
 89      if (l > r || L == R) return;//l和r是问题的编号
 90      int mid = (L + R) >> 1;
 91
 92      while (data[pos + 1].val <= mid && pos < cnt){//直接模拟
 93            add(data[pos + 1].x, data[pos + 1].y, 1);
 94            pos++;
 95      }
 96      while (data[pos].val > mid){
 97            add(data[pos].x, data[pos].y , -1);
 98            pos--;
 99      }
100      int cnt = 0;
101      for (int i = l; i <= r; i++){
102          if (query(id[i]) > q[id[i]].K - 1){
103             mark[i] = 1;
104             Ans[id[i]] = mid;
105             cnt++;
106          }else mark[i] = 0;
107      }
108      int l1 = l, l2 = l + cnt;
109      for (int i = l; i <= r; i++)
110      if (mark[i]) tmp[l1++] = id[i];
111      else tmp[l2++] = id[i];
112      //分成两部分继续整体二分
113      for (int i = l; i <= r; i++) id[i] = tmp[i];
114      solve(l, l1 - 1, L, mid);
115      solve(l1, l2 - 1, mid + 1, R);
116 }
117
118 void init(){
119     memset(mark, 0, sizeof(mark));
120     memset(c, 0, sizeof(c));
121     scanf("%d%d", &n, &m);
122     Maxv = 0;
123     cnt = 0;
124     for (int i = 1; i <= n; i++)
125     for (int j = 1; j <= n; j++){
126         scanf("%d", &data[++cnt].val);
127         data[cnt].x = i;//横纵坐标
128         data[cnt].y = j;
129         Maxv = max(data[cnt].val, Maxv);
130     }
131     sort(data + 1, data + 1 + cnt);
132 }
133 void work(){
134      for (int i = 1; i <= m; i++){
135          scanf("%d%d%d%d%d", &q[i].x1, &q[i].y1, &q[i].x2, &q[i].y2, &q[i].K);
136      }
137      for (int i = 1; i <= m; i++) id[i] = i;//问题序列
138      solve(1, m, 0, Maxv + 1);
139      for (int i = 1; i <= m; i++) printf("%d\n", Ans[i]);
140 }
141
142 int main(){
143
144     init();
145     work();
146     return 0;
147 }

时间: 2024-10-07 04:40:56

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

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

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2738 [题目大意] 给出一个方格图,询问要求求出矩阵内第k小的元素 [题解] 我们对答案的大小进行整体二分,用二维树状数组维护二维区间和, 将超过数量的分治到左区间,不满足的分治到右区间即可. [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std;

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

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

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

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

HDU_2642_二维树状数组

Stars Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/65536 K (Java/Others)Total Submission(s): 1628    Accepted Submission(s): 683 Problem Description Yifenfei is a romantic guy and he likes to count the stars in the sky.To make the pr

【IOI2001】【poj1195】Mobile phones(二维树状数组)

一维树状数组维护的是区间和,最后统计的是1~x数的和,而二维树状数组维护的是一个面的和,最后统计的是 (1,1)~(x,y)区域内数的和 (x,y)所维护的面大小由x,y共同决定,x决定高度,y决定宽度 add和query操作的两层循环结合二分图理解比较直观 如何分呢?首先,我们按照X坐标,把整个表格分成部分,并对每个部分按照X坐标继续二分下去,同时,我们将分得的每个部分再按Y坐标进行二分,并记下最终分得的每个部分的移动电话总数. “多重二分”的结果,实际上类似于一维情况下二分的结果,也是形成一

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

POJ 1195 Mobile phones(二维树状数组)

题目链接:POJ 1195 题意: 给出一个S*S的矩阵(行.列号从1开始),每个元素初始值为0,有两种操作:一种是第X行第Y列元素值加A:另一种是查询给定范围矩阵的所有元素之和(L<=X<=R,B<=Y<=T). 分析: 查询给定范围矩阵的所有元素之和是二维区间和,可以转换为二维前缀和求值.类比一维前缀和求法,二维区间和S(L, B, R, T) = S(1, 1, R, T) - S(1 ,1, L-1, T) - S(1, 1, R, B-1) + S(1, 1, L-1,

POJ 2155 Matrix(二维树状数组,绝对具体)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

HDU 5465 Clarke and puzzle Nim游戏+二维树状数组

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5465 Clarke and puzzle Accepts: 42 Submissions: 269 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 克拉克是一名人格分裂患者.某一天,有两个克拉克(aa和bb)在玩一个方格游戏. 这个方格是一个n*mn∗m的矩阵,每个格子里有一