【清澄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 }
View Code

 

posted @ 2015-03-14 16:58  TCtower  阅读(280)  评论(0编辑  收藏  举报