Uva7716 The Cure(CDQ分治 + 整体二分)

本文介绍了解决Uva7716 The Cure问题的方法,通过CDQ分治算法和二分查找技巧,在n*n矩阵中高效查询特定元素。详细讲解了如何构建和查询矩阵,实现对不同查询的有效处理。
/**
Uva7716 The Cure

题意: 给一个n * n的矩阵,有q个查询,每次查询r,c,s,k表示已(r,c)为右上角 大小为s的正方形中 第k小的元素

思路:可用CDQ分治, 二分所有值的答案, 对于答案在[L, R]的矩阵,将[L, mid]的矩阵用1填充,查询满足条件的
放进[L, mid]递归处理, 不满足条件的放进[mid, R]中去处理
*/
#include<bits/stdc++.h>
const int maxn = 260;
const int maxq = 2e5 + 5e4 + 10;
const int INF = 1e9 + 10;
using namespace std;

struct query {
    int x1, x2, y1, y2, k;
    void input() { scanf("%d %d %d %d", &x1, &y1, &x2, &k); y2 = y1 + x2 - 1; x2 = x1 + x2 - 1; }
} res[maxq];
typedef struct point {
    int x, y, val;
    point() {}
    point(int x, int y, int v) : x(x), y(y), val(v) {}
} operation;
int n, m, kase = 1, T, q;
int mat[maxn][maxn];
point point_val[maxn * maxn];
operation opt[4 * maxq + maxn * maxn];
int s[maxq], can[maxq], notcan[maxq];
int tot, rec[maxq], C[maxn];
int b[maxn * maxn], all, cnt;
int py[maxn * maxn + maxq * 2];
map<int, int> idx_first, idx_last;

bool cmp1(point p1, point p2) {
    if(p1.x != p2.x) return p1.x < p2.x;
    if(p1.y != p2.y) return p1.y < p2.y;
    return p1.val > p2.val;
}
bool cmp2(point p1, point p2) { return p1.val < p2.val; }
void update(int x, int data, int tal) { for( ; x <= tal; x += x & -x) C[x] += data; }
int get_sum(int x) { int ans = 0; for(; x; x -= x & -x) ans += C[x]; return ans; }


void solve(int l, int r, int from, int to) {
    if(from == to) return ;
    int mid = (l + r) >> 1, v1 = b[l], v2 = b[mid];
    int id1 = idx_first[v1], id2 = idx_last[v2];
    int num = 0, t1 = 0, t2 = 0, now = from, toty = 0, it = 0;
    for(int i = id1; i <= id2; i++) {
        opt[num++] = point(point_val[i].x, point_val[i].y, 1);
        py[toty++] = point_val[i].y;
    }
    for(int i = from; i < to; i++) {
        int ix = s[i];
        opt[num++] = point(res[ix].x1 - 1, res[ix].y1 - 1, 0);
        opt[num++] = point(res[ix].x2, res[ix].y1 - 1, 0);
        opt[num++] = point(res[ix].x1 - 1, res[ix].y2, 0);
        opt[num++] = point(res[ix].x2, res[ix].y2, 0);
        py[toty++] = res[ix].y1 - 1;
        py[toty++] = res[ix].y2;
    }
    sort(opt, opt + num, cmp1);
    sort(py, py + toty);
    toty = unique(py, py + toty) - py;
    for(int i = 1; i <= toty; i++) C[i] = 0;
    for(int i = 0; i < num; i++) {
        int ind = upper_bound(py, py + toty, opt[i].y) - py;
        if(opt[i].val) update(ind, 1, toty);
        else mat[opt[i].x][opt[i].y] = get_sum(ind);
    }
    for(int i = from; i < to; i++) {
        int ix = s[i]; query p = res[ix];
        int x = p.x1 - 1, y = p.y1 - 1, X = p.x2, Y = p.y2;
        int tal = mat[X][Y] - mat[x][Y] - mat[X][y] + mat[x][y];
        if(tal >= p.k) { rec[ix] = min(rec[ix], v2); can[t1++] = ix; }
        else { notcan[t2++] = ix; res[ix].k -= tal; }
    }
    for(int i = 0; i < t1; i++) s[now++] = can[i];
    for(int i = 0; i < t2; i++) s[now++] = notcan[i];
    if(l != r) solve(mid + 1, r, from + t1, to);
    if(l == r) return ;
    solve(l, mid, from, from + t1);
}

int main() {
    while(scanf("%d", &n) != EOF) {
        cnt = all = 0;
        idx_first.clear(); idx_last.clear();
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) {
                scanf("%d", &mat[i][j]);
                point_val[cnt++] = point(i, j, mat[i][j]);
                b[all++] = mat[i][j];
                mat[i][j] = 0;
            }
        }
        sort(point_val, point_val + cnt, cmp2);
        sort(b, b + all); all = unique(b, b + all) - b;
        for(int i = 0; i < cnt; i++) {
            int val = point_val[i].val;
            if(!idx_first.count(val)) idx_first[val] = i;
            idx_last[val] = i;
        }
        scanf("%d", &q);
        for(int i = 1; i <= q; i++) { res[i].input(); s[i] = i; rec[i] = INF; }
        solve(0, all - 1, 1, q + 1);
        for(int i = 1; i <= q; i++) printf("%d\n", rec[i]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值