zoukankan      html  css  js  c++  java
  • 洛谷 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^9log 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
    ",ans[i]);
        return 0;
    }
    

    2018.11.1

  • 相关阅读:
    vue-router路由器的使用
    组件间数据传递
    引用模块和动态组件
    vue自定义全局和局部指令
    vue实例的属性和方法
    vue生命周期以及vue的计算属性
    vue 发送ajax请求
    安装vue-cli脚手架
    vue指令详解
    scrapy-redis组件的使用
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9892900.html
Copyright © 2011-2022 走看看