zoukankan      html  css  js  c++  java
  • 【bzoj2738】矩阵乘法 整体二分 二维树状数组

    【bzoj2738】矩阵乘法

    Description

      给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。

    Input

     
      第一行两个数N,Q,表示矩阵大小和询问组数;
    接下来N行N列一共N*N个数,表示这个矩阵;
    再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。

    Output

      对于每组询问输出第K小的数。

    Sample Input

    2 2
    2 1
    3 4
    1 2 1 2 1
    1 1 2 2 3

    Sample Output

    1
    3

    HINT

    矩阵中数字是109以内的非负整数;
    20%的数据:N<=100,Q<=1000;
    40%的数据:N<=300,Q<=10000;
    60%的数据:N<=400,Q<=30000;
    100%的数据:N<=500,Q<=60000。

    题解:

    二分询问的答案mid,将数值小等mid的全部插入二维树状数组

    然后查询每个矩阵内的元素个数,若数量>K-1则放左边,否则放右边

    继续向下分治,左边二分l-mid,右边mid-r,当然,首先按键值排好序(是指输入的a数组),

    然后下面在继续分。

     1 #include<cstring>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstdio>
     6 
     7 
     8 #define N 507
     9 #define M 60007
    10 using namespace std;
    11 inline int read()
    12 {
    13     int x=0,f=1;char ch=getchar();
    14     while(ch>'9'||ch<'0'){if (ch=='-')f=-1;ch=getchar();}
    15     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    16     return x*f;
    17 }
    18 
    19 int n,m,top,T;
    20 int id[M],tmp[M],ans[M],tr[N][N];
    21 bool mark[M];
    22 struct Node1
    23 {
    24     int x,y,num;
    25 }a[N*N];
    26 struct Node2
    27 {
    28     int x1,x2,y1,y2,k;
    29 }q[M];
    30 
    31 bool cmp(Node1 x,Node1 y){return x.num<y.num;}
    32 inline int lowbit(int x){return x&(-x);}
    33 void update(int x,int y,int num)
    34 {
    35     for (int i=x;i<=n;i+=lowbit(i))
    36         for (int j=y;j<=n;j+=lowbit(j))
    37             tr[i][j]+=num;
    38 }
    39 int ask(int x,int y)
    40 {
    41     int res=0;
    42     for (int i=x;i>=1;i-=lowbit(i))
    43         for (int j=y;j>=1;j-=lowbit(j))
    44             res+=tr[i][j];
    45     return res;            
    46 }
    47 int query(int k)
    48 {
    49     int x1=q[k].x1,x2=q[k].x2,y1=q[k].y1,y2=q[k].y2;
    50     return ask(x2,y2)+ask(x1-1,y1-1)-ask(x1-1,y2)-ask(x2,y1-1);
    51 }
    52 void solve(int l,int r,int L,int R)
    53 {
    54     if (l>r||L==R) return;
    55     int mid=(L+R)>>1;
    56     while(a[T+1].num<=mid&&T<top)update(a[T+1].x,a[T+1].y,1),T++;
    57     while(a[T].num>mid)update(a[T].x,a[T].y,-1),T--;//将比mid小或等的都放入二维树状数组中。 
    58     int cnt=0;
    59     for (int i=l;i<=r;i++)
    60     {
    61         if (query(id[i])>q[id[i]].k-1) mark[i]=1,ans[id[i]]=mid,cnt++;
    62         else mark[i]=0;
    63     }
    64     int l1=l,l2=l+cnt;
    65     for (int i=l;i<=r;i++)//若数量>K-1则放左边,否则放右边
    66         if (mark[i])tmp[l1++]=id[i];
    67         else tmp[l2++]=id[i];
    68     for (int i=l;i<=r;i++)id[i]=tmp[i];
    69     solve(l,l1-1,L,mid);solve(l1,l2-1,mid+1,R);    
    70 }
    71 int main()
    72 {
    73     n=read(),m=read();
    74     int mx=0;
    75     for (int i=1;i<=n;i++)
    76         for (int j=1;j<=n;j++)
    77         {
    78             a[++top].x=i,a[top].y=j,a[top].num=read();
    79             mx=max(a[top].num,mx);
    80         }
    81     sort(a+1,a+top+1,cmp);//按照点值大小来排序。 
    82     for (int i=1;i<=m;i++)
    83         q[i].x1=read(),q[i].y1=read(),q[i].x2=read(),q[i].y2=read(),q[i].k=read();
    84     for (int i=1;i<=m;i++)id[i]=i;
    85     solve(1,m,0,mx+1);
    86     for (int i=1;i<=m;i++)
    87         printf("%d
    ",ans[i]);        
    88 }
  • 相关阅读:
    《Linux权威指南》阅读笔记(3)
    adb命令篇 (转载)
    3.抓包神器Fiddler简介(转载)
    python-文件基本操作(一) (转载)
    python+requests实现接口测试
    python+requests实现接口测试
    12306登录爬虫 cookies版本
    爬虫3 requests之json 把json数据转化为字典
    爬虫3 requests基础之下载图片用content(二进制内容)
    爬虫3 requests基础之 乱码编码问题
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7976570.html
Copyright © 2011-2022 走看看