bzoj2738 矩阵乘法 cdq分治

Description


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

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

Solution


作为一个主席树/树套树爱好者表示这道题主席树写起来非常爽
但是如果是主席树做法就没啥好讲了,于是写了cdq分治的做法

一个非常容易想到的办法就是二分一个mid,用树状数组统计子矩阵中插入数字的数量
一开始错了是输出把T打成了n,( ╯□╰ )
好像也没啥好讲的。。。

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define lowbit(x) ((x)&(-(x)))

const int N=605;
const int G=80005;

struct Q {int x1,y1,x2,y2,k,id,ans;} q[G],tmp[G];
struct data {int x,y,w;} a[N*N];

int c[N][N],rec[G];
int now,tot,n;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add(data a,int v) {
    for (int i=a.x;i<=n;i+=lowbit(i)) {
        for (int j=a.y;j<=n;j+=lowbit(j)) {
            c[i][j]+=v;
        }
    }
}

int get(int x,int y) {
    int ret=0;
    for (int i=x;i;i-=lowbit(i)) {
        for (int j=y;j;j-=lowbit(j)) {
            ret+=c[i][j];
        }
    }
    return ret;
}

void solve(int l,int r,int L,int R) {
    if (l>r) return ;
    if (L==R) {
        rep(i,l,r) q[i].ans=L;
        return ;
    }
    int mid=(L+R)>>1;
    for (;now<tot&&a[now+1].w<=mid;) add(a[++now],1);
    for (;now&&a[now].w>mid;) add(a[now--],-1);
    int cnt=0;
    rep(i,l,r) {
        int res=get(q[i].x2,q[i].y2)+get(q[i].x1-1,q[i].y1-1);
        res=res-get(q[i].x2,q[i].y1-1)-get(q[i].x1-1,q[i].y2);
        if (res>=q[i].k) {
            cnt++; rec[i]=1;
        } else rec[i]=2;
    }
    int tl=l,tr=l+cnt;
    rep(i,l,r) if (rec[i]==1) tmp[tl++]=q[i];
    else tmp[tr++]=q[i];
    rep(i,l,r) q[i]=tmp[i];
    solve(l,l+cnt-1,L,mid);
    solve(l+cnt,r,mid+1,R);
}

bool cmp1(data a,data b) {
    return a.w<b.w;
}

bool cmp2(Q a,Q b) {
    return a.id<b.id;
}

int main(void) {
    n=read(); int T=read();
    rep(i,1,n) rep(j,1,n) a[++tot]=(data) {i,j,read()};
    std:: sort(a+1,a+tot+1,cmp1);
    rep(i,1,T) q[i]=(Q) {read(),read(),read(),read(),read(),i};
    solve(1,T,1,a[tot].w);
    std:: sort(q+1,q+T+1,cmp2);
    rep(i,1,T) printf("%d\n", q[i].ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/80530388