洛谷 P1527 [国家集训队]矩阵乘法

矩阵第k小

一道练习整体二分的比较好的题

这道题把序列查询区间第(k)小搬到了矩阵上,但是仍然满足二分性质,所以我们还是可以整体二分

而我们沿用序列上的做法,把点和询问都离线下来,揉在一起整体二分

唯一不一样的地方就是需要二维树状数组,这个很好理解吧qwq

复杂度(O(Qlog^3n))

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
const int N = 500;
const int M = 6e4;
const int N2 = 250000;
const int INF = 1e9;
using namespace std;
struct node
{
    int x1,y1,x2,y2,k,id;
}q[M + N2 + 5],q1[M + N2 + 5],q2[M + N2 + 5];
int n,m,a[N + 5][N + 5],ans[M + 5],c[N + 5][N + 5],cnt;
int lowbit(int x)
{
    return x & (-x);
}
void add(int x,int y,int s)
{
    for (int i = x;i <= n;i += lowbit(i))
        for (int j = y;j <= n;j += lowbit(j))
            c[i][j] += s;
}
int query(int x,int y)
{
    if (!x || !y)
        return 0;
    int ans = 0;
    for (int i = x;i;i -= lowbit(i))
        for (int j = y;j;j -= lowbit(j))
            ans += c[i][j];
    return ans;
}
int query_sum(int x1,int y1,int x2,int y2)
{
    return query(x2,y2) - query(x1 - 1,y2) - query(x2,y1 - 1) + query(x1 - 1,y1 - 1);
}
void solve(int l,int r,int L,int R)
{
    if (L > R)
        return;
    if (l == r)
    {
        for (int i = L;i <= R;i++)
            if (q[i].id)
                ans[q[i].id] = l;
        return;
    }
    int mid = l + r >> 1,cnt1 = 0,cnt2 = 0;
    for (int i = L;i <= R;i++)
        if (q[i].id == 0)
        {
            if (q[i].k <= mid)
            {
                add(q[i].x1,q[i].y1,1);
                q1[++cnt1] = q[i];
            }
            else
                q2[++cnt2] = q[i];
        }
        else
        {
            int x = query_sum(q[i].x1,q[i].y1,q[i].x2,q[i].y2);
            if (x >= q[i].k)
                q1[++cnt1] = q[i];
            else
            {
                q[i].k -= x;
                q2[++cnt2] = q[i];
            }
        }
    for (int i = 1;i <= cnt1;i++)
        if (q1[i].id == 0)
            add(q1[i].x1,q1[i].y1,-1);
    for (int i = L;i <= L + cnt1 - 1;i++)
        q[i] = q1[i - L + 1];
    for (int i = L + cnt1;i <= R;i++)
        q[i] = q2[i - L - cnt1 + 1];
    solve(l,mid,L,L + cnt1 - 1);
    solve(mid + 1,r,L + cnt1,R);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= n;j++)
        {
            scanf("%d",&a[i][j]);
            q[++cnt] = (node){i,j,0,0,a[i][j],0};
        }
    for (int i = 1;i <= m;i++)
    {
        cnt++;
        scanf("%d%d%d%d%d",&q[cnt].x1,&q[cnt].y1,&q[cnt].x2,&q[cnt].y2,&q[cnt].k);
        q[cnt].id = i;
    }
    solve(0,INF,1,cnt);
    for (int i = 1;i <= m;i++)
        printf("%d
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/sdlang/p/13068063.html