BZOJ 2738 矩阵乘法 分块

题目大意:给定一个矩阵,多次求一个子矩阵中的第k小

正解:CDQ分治 不会 

二维莫队? 不会 

于是果断分块大法好(又是

我们将这n*n个数排序 分n次插入 每次插入n个

每次插入后 去链表上处理尚未出解的询问(我懒得写链表写了并查集) 如果当前询问的子矩阵内已经插入大于等于k个数 那么答案一定在当次插入的n个数中 暴力查找即可

时间复杂度O(n^3+nq) 好卡……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 510
using namespace std;
struct abcd{
    int x,y,num;
    bool operator < (const abcd &Y) const
    {
        return num < Y.num ;
    }
}a[M*M];
struct query{
    int x1,y1,x2,y2,k;
}q[60600];
int n,m;
int map[M][M],cnt[M][M],sum[M][M],ans[60600];
int fa[60600];
int Find(int x)
{
    if(!fa[x]||fa[x]==x)
        return fa[x]=x;
    return fa[x]=Find(fa[x]);
}
int main()
{
    int i,j,k;
    cin>>n>>m;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        {
            scanf("%d",&map[i][j]);
            a[i*n-n+j].x=i;
            a[i*n-n+j].y=j;
            a[i*n-n+j].num=map[i][j];
        }
    for(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);
    sort(a+1,a+n*n+1);
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            abcd &temp=a[i*n-n+j];
            cnt[temp.x][temp.y]=1;
        }
        for(j=1;j<=n;j++)
            for(k=1;k<=n;k++)
                sum[j][k]=cnt[j][k]+sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1];
        for(k=Find(1);k<=m;k=Find(k+1))
        {
            int x1=q[k].x1-1;
            int y1=q[k].y1-1;
            int x2=q[k].x2;
            int y2=q[k].y2;
            int temp=sum[x2][y2]+sum[x1][y1]-sum[x1][y2]-sum[x2][y1];
            if(temp<q[k].k)
                continue;
            temp-=q[k].k;
            for(j=n;j;j--)
                if(a[i*n-n+j].x>x1&&a[i*n-n+j].y>y1&&a[i*n-n+j].x<=x2&&a[i*n-n+j].y<=y2)
                    if(!temp--)
                    {
                        ans[k]=a[i*n-n+j].num;
                        break;
                    }
            fa[k]=k+1;
        }
    }
    for(i=1;i<=m;i++)
        printf("%d\n",ans[i]);
}


你可能感兴趣的:(分块,bzoj,bzoj2738)