洛谷P1527[国家集训队]矩阵乘法(整体二分+树状数组)

整体二分经典题。对于一个$mid$,把所有小于$mid$的数染色,检查区间和即可。只是$O(qlog^3n)$需要卡常。二维树状数组是必须的,还有一个小技巧是:把所有数和对应的位置排序后,用一个cur记录一下现在树状数组的状态是1~cur染色过,每次移动cur,这样就省去了清空的复杂度。

#include<cstdio>
#include<algorithm>
using namespace std;
char rB[1<<21],*rS,*rT,wB[(1<<21)+50];
int wp=-1;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
short buf[15];
inline void wt(int x){
    if(wp>(1<<21))flush();
    short l=-1;
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    wB[++wp]=x|48;
    while(l>=0)wB[++wp]=buf[l--]|48;
    wB[++wp]='\n';
}
const int N=505;
const int M=60005;
int c[N][N],n,cur=0,s[M],b[N*N];
struct point{
    int x,y,k;
}a[N*N];
struct query{
    int x1,y1,x2,y2,k,id;
}Q[M],Q1[M],Q2[M];
inline bool cmp(point a,point b){return a.k<b.k;}
inline void add(int x,int y,short k){
    for(int i=x,j;i<=n;i+=i&-i)
        for(j=y;j<=n;j+=j&-j)c[i][j]+=k;
}
inline int sum(int x,int y){
    int i,j,s=0;
    for(i=x;i;i^=i&-i)
        for(j=y;j;j^=j&-j)s+=c[i][j];
    return s;
}
void solve(int L,int R,int l,int r){
    if(l>r)return;
    if(L==R){
        for(int i=l;i<=r;++i)s[Q[i].id]=b[L];
        return;
    }
    int M=L+R>>1,i,cnt1=0,cnt2=0;
    while(a[cur].k<=M){
        ++cur;
        add(a[cur].x,a[cur].y,1);
    }
    for(;a[cur].k>M;--cur)add(a[cur].x,a[cur].y,-1);
    for(i=l;i<=r;++i)if(sum(Q[i].x2,Q[i].y2)-sum(Q[i].x2,Q[i].y1-1)-sum(Q[i].x1-1,Q[i].y2)+sum(Q[i].x1-1,Q[i].y1-1)>=Q[i].k)Q1[cnt1++]=Q[i];
    else Q2[cnt2++]=Q[i];
    for(i=0;i<cnt1;++i)Q[l+i]=Q1[i];
    for(i=0;i<cnt2;++i)Q[l+cnt1+i]=Q2[i];
    solve(L,M,l,l+cnt1-1);
    solve(M+1,R,l+cnt1,r);
}
int main(){
    int q,m,i,j;
    n=rd();q=rd();
    for(i=1;i<=n;++i)
        for(j=1;j<=n;++j){a[(i-1)*n+j].x=i;a[(i-1)*n+j].y=j;b[(i-1)*n+j]=a[(i-1)*n+j].k=rd();}
    sort(b+1,b+n*n+1);m=unique(b+1,b+n*n+1)-b-1;
    for(i=1;i<=n*n;++i)a[i].k=lower_bound(b+1,b+m+1,a[i].k)-b;
    sort(a+1,a+n*n+1,cmp);
    for(i=0;i<q;++i){Q[i].x1=rd();Q[i].y1=rd();Q[i].x2=rd();Q[i].y2=rd();Q[i].k=rd();Q[i].id=i;}
    solve(1,m,0,q-1);
    for(i=0;i<q;++i)wt(s[i]);
    flush();
    return 0;
}
View Code

 

posted @ 2019-08-20 12:59  wangyuchen  阅读(152)  评论(0编辑  收藏  举报