BZOJ 2738 矩阵乘法 整体二分

题意:

  给出n*n的矩阵,求出子矩阵的k小值

分析:

  真理:当一个题的题目名是一个算法时,这道题多半和这个算法没啥关系。

  其实就是把整体二分的步骤放到二维了。我们需要一个二维线段树来查询操作。

  其他嘛,直接把矩阵抻成序列即可。(但要记得记录二维坐标)

代码:

#include<bits/stdc++.h>
using namespace std;
const int M=505;
const int N=60005;
int n,m,n2,tot,now;
struct node{int x,y,v;}v[M*M];
int q1[N],q2[N],q3[N],q4[N],qk[N];
int ans[N],s[M][M],p[N],q[N],sm[N];
bool cmp(node a,node b){
    return a.v<b.v;
} void plu(int x,int y,int val){
    for(int i=x;i<=n;i+=i&-i)
    for(int j=y;j<=n;j+=j&-j)
    {s[i][j]+=val;} return ;
} int query(int x,int y){
    int r=0;for(int i=x;i;i-=i&-i)
    for(int j=y;j;j-=j&-j)
    {r+=s[i][j];}return r;
} void solve(int l,int r,int L,int R){
    if(l>r) return ;
    if(L==R){
        for(int i=l;i<=r;i++)
        {ans[p[i]]=v[L].v;}return ;
    } int mid=(L+R)>>1,md=l-1;
    while(now<mid) now++,
    plu(v[now].x,v[now].y,1);
    while(now>mid)
    plu(v[now].x,v[now].y,-1),now--;
    for(int i=l;i<=r;i++){
        sm[p[i]]=query(q1[p[i]]-1,q2[p[i]]-1)+
        query(q3[p[i]],q4[p[i]])-
        query(q1[p[i]]-1,q4[p[i]])-
        query(q3[p[i]],q2[p[i]]-1);
        if(sm[p[i]]>=qk[p[i]]) md++;
    } int l1=l,l2=md+1;
    for(int i=l;i<=r;i++)
    if(sm[p[i]]>=qk[p[i]]) q[l1++]=p[i];
    else q[l2++]=p[i];
    for(int i=l;i<=r;i++) p[i]=q[i];
    solve(l,md,L,mid);solve(md+1,r,mid+1,R);
} int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    scanf("%d",&v[++n2].v),v[n2].x=i,v[n2].y=j;
    sort(v+1,v+1+n2,cmp);
    for(int i=1;i<=m;i++)
    scanf("%d%d%d%d%d",&q1[i],&q2[i],&q3[i],
    &q4[i],&qk[i]),p[i]=i;solve(1,m,1,n2);
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2018-12-25 23:30  杜宇一声  阅读(154)  评论(0编辑  收藏  举报