1. 程式人生 > >洛谷 P1527 [國家集訓隊]矩陣乘法 解題報告

洛谷 P1527 [國家集訓隊]矩陣乘法 解題報告

P1527 [國家集訓隊]矩陣乘法

題目描述

給你一個\(N*N\)的矩陣,不用算矩陣乘法,但是每次詢問一個子矩形的第\(K\)小數。

輸入輸出格式

輸入格式:

第一行兩個數\(N,Q\),表示矩陣大小和詢問組數;

接下來\(N\)\(N\)列一共\(N*N\)個數,表示這個矩陣;

再接下來\(Q\)行每行\(5\)個數描述一個詢問:\(x1,y1,x2,y2,k\)表示找到以\((x1,y1)\)為左上角、以\((x2,y2)\)為右下角的子矩形中的第\(K\)小數。

輸出格式:

對於每組詢問輸出第\(K\)小的數。

說明

矩陣中數字是\(10^9\)以內的非負整數;

\(20\%\)

的資料:\(N<=100,Q<=1000\)

\(40\%\)的資料:\(N<=300,Q<=10000\)

\(60\%\)的資料:\(N<=400,Q<=30000\)

\(100\%\)的資料:\(N<=500,Q<=60000\)


整體二分真有趣。

直接把整體二分裡面的改成二維樹狀陣列就可以了

複雜度\(O((N^2+M)\log10^9\log N^2)\)


Code:

#include <cstdio>
const int N=502;
const int M=310010;
const int inf=0x3f3f3f3f;
struct node{int op,a,b,c,d,k;}q[M],ql[M],qr[M];
int s[N][N],n,m,Q,ans[M];
void add(int x,int y,int d)
{
    for(int i=x;i<=n;i+=i&-i)
        for(int j=y;j<=n;j+=j&-j)
            s[i][j]+=d;
}
int query(int x,int y)
{
    int sum=0;
    for(int i=x;i;i-=i&-i)
        for(int j=y;j;j-=j&-j)
            sum+=s[i][j];
    return sum;
}
#define rep(i,a,b) for(int i=a;i<=b;i++)
void divide(int l,int r,int s,int t)
{
    if(s>t)return;
    if(l==r){rep(i,s,t)ans[q[i].op]=l;return;}
    int mid=l+r>>1,lp=0,rp=0;
    rep(i,s,t)
    {
        if(q[i].op)
        {
            int p=query(q[i].c,q[i].d)-query(q[i].c,q[i].b-1)
                 -query(q[i].a-1,q[i].d)+query(q[i].a-1,q[i].b-1);
            if(q[i].k<=p) ql[++lp]=q[i];
            else qr[++rp]=q[i],qr[rp].k-=p;
        }
        else
        {
            if(q[i].k<=mid) add(q[i].a,q[i].b,1),ql[++lp]=q[i];
            else qr[++rp]=q[i];
        }
    }
    rep(i,s,t) if(!q[i].op&&q[i].k<=mid) add(q[i].a,q[i].b,-1);
    rep(i,s,s+lp-1) q[i]=ql[i+1-s];
    rep(i,s+lp,t) q[i]=qr[i+1-s-lp];
    divide(l,mid,s,s+lp-1),divide(mid+1,r,s+lp,t);
}
int main()
{
    scanf("%d%d",&n,&Q);
    rep(i,1,n) rep(j,1,n) ++m,scanf("%d",&q[m].k),q[m].a=i,q[m].b=j;
    rep(i,1,Q) ++m,scanf("%d%d%d%d%d",&q[m].a,&q[m].b,&q[m].c,&q[m].d,&q[m].k),q[m].op=i;
    divide(0,inf,1,m);
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}

2018.11.1