• bzoj2738 矩阵乘法


    2738: 矩阵乘法

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 1828  Solved: 792
    [Submit][Status][Discuss]

    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

    100%的数据:N<=500,Q<=60000。

    分析:很容易看出是整体二分吧,只不过从一维变成了二维.

       我用bzoj3110的方法去做,开了一个二维线段树,结果T了,原因是每次都要枚举行,在每一行上进行操作,在枚举上非常浪费时间. 怎么办呢?树状数组呗......只涉及到单点修改,区间查询. 用二维树状数组维护即可.

       结果还是T了......为什么呢,因为我直接用了long long.事实上int就可以了.  这也启发了我如果确定不可能爆int的情况下不要轻易用long long!可能爆并且时间很宽松的话,全部上long long可以保证不出错.  否则就只能把可能会爆int的变成long long咯.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 510;
    int n,q,a[maxn][maxn],sum[maxn][maxn << 2],tag[maxn][maxn << 2];
    int L[maxn][maxn << 2],R[maxn][maxn << 2],id[60010],cnt,tot,ans[60010];
    int t1[60010],t2[60010],cover[maxn][maxn << 2],c[maxn][maxn];
    
    struct node
    {
        int l1,l2,r1,r2,k;
    }e[60010];
    
    struct node2
    {
        int x,y,v;
    }e2[maxn * maxn];
    
    bool cmp(node2 a,node2 b)
    {
        return a.v < b.v;
    }
    
    void add(int x,int y,int v)
    {
        for (int i = x; i <= n; i += i & (-i))
            for (int j = y; j <= n; j += j & (-j))
                c[i][j] += v;
    }
    
    int Query(int x,int y)
    {
        int res = 0;
        for (int i = x; i; i -= i & (-i))
            for (int j = y; j; j -= j & (-j))
                res += c[i][j];
        return res;
    }
    
    int query(int l1,int r1,int l2,int r2)
    {
        return Query(l2,r2) - Query(l1 - 1,r2) - Query(l2,r1 - 1) + Query(l1 - 1,r1 - 1);
    }
    
    void solve(int L,int R,int l,int r)
    {
        if (L > R)
            return;
        if (l == r)
        {
            for (int i = L; i <= R; i++)
            {
                int temp = id[i];
                ans[temp] = e2[l].v;
            }
            return;
        }
        int p1 = 0,p2 = 0;
        int mid = (l + r) >> 1;
        for (int i = l; i <= mid; i++)
            add(e2[i].x,e2[i].y,1);
        for (int i = L; i <= R; i++)
        {
            int res = 0,temp = id[i];
            res += query(e[temp].l1,e[temp].r1,e[temp].l2,e[temp].r2);
            if (res < e[temp].k)
            {
                e[temp].k -= res;
                t2[++p2] = temp;
            }
            else
                t1[++p1] = temp;
        }
        for (int i = l; i <= mid; i++)
            add(e2[i].x,e2[i].y,-1);
        for (int i = 1; i <= p1; i++)
            id[i + L - 1] = t1[i];
        for (int i = 1; i <= p2; i++)
            id[i + L + p1 - 1] = t2[i];
        solve(L,L + p1 - 1,l,mid);
        solve(L + p1,R,mid + 1,r);
    }
    
    int main()
    {
        freopen("test.txt","r",stdin);
        scanf("%d%d",&n,&q);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
            {
                scanf("%d",&a[i][j]);
                e2[++tot].v = a[i][j];
                e2[tot].x = i;
                e2[tot].y = j;
            }
        sort(e2 + 1,e2 + 1 + tot,cmp);
        for (int i = 1; i <= q; i++)
        {
            scanf("%d%d%d%d%d",&e[i].l1,&e[i].r1,&e[i].l2,&e[i].r2,&e[i].k);
            id[i] = i;
        }
        solve(1,q,1,n * n);
        for (int i = 1; i <= q; i++)
            printf("%d
    ",ans[i]);
    
        return 0;
    }
  • 相关阅读:
    poj2928:素数回文数的个数
    R语言学习中的小bug:R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数
    poj3247:回文素数
    Python爬虫之BeautifulSoap的用法
    python jieba库的使用说明
    彻底弄懂python编码
    第八周助教总结
    python中数组用法
    python列表操作大全
    python—各种常用函数及库
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8585567.html
Copyright © 2020-2023  润新知