[国家集训队]矩阵乘法 整体二分

很好的一道题,令人大开眼界。

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define setIO(s) freopen(s".in","r",stdin) 
#define maxn 1000000
#define N 600
using namespace std;
int n,Q,idx,q[maxn],tl[maxn],tr[maxn],answer[maxn],cur[maxn]; 
struct MAT{
    int x,y,w; 
}mat[maxn]; 
int cmp(MAT a,MAT b){ return a.w<b.w;}
struct Query{
    int a,b,c,d,k; 
}ask[maxn];
struct BIT{
    int C[N][N];
    int lowbit(int x){ return x&(-x);}
    void add(int x,int y,int k)
    {
        for(int i=x;i<=n;i+=lowbit(i))
            for(int j=y;j<=n;j+=lowbit(j)) C[i][j]+=k;
    }
    int query(int x,int y)
    {
        int ans=0;
        for(int i=x;i>0;i-=lowbit(i))
            for(int j=y;j>0;j-=lowbit(j)) ans+=C[i][j];
        return ans; 
    }
    int ask(Query a)
    {
        return query(a.c,a.d)-query(a.c,a.b-1)-query(a.a-1,a.d)+query(a.a-1,a.b-1); 
    }
}tree;
void solve(int x,int y,int l,int r){
    if(x>y||l>r) return;
    if(l==r){
        for(int i=x;i<=y;++i) answer[q[i]]=mat[l].w;
        return; 
    }
    int mid=(l+r)>>1;
    for(int i=l;i<=mid;++i) tree.add(mat[i].x,mat[i].y,1);
    int left=0,right=0,s,u;
    for(int i=x;i<=y;++i){
        u=q[i];
        s=cur[u]+tree.ask(ask[u]);  
        if(s>=ask[u].k) tl[++left]=u;
        else tr[++right]=u,cur[u]=s; 
    }
    int qcnt=x-1;
    for(int i=1;i<=left;++i) q[++qcnt]=tl[i];
    for(int i=1;i<=right;++i) q[++qcnt]=tr[i];
    for(int i=l;i<=mid;++i) tree.add(mat[i].x,mat[i].y,-1);
    solve(x,x+left-1,l,mid),solve(x+left,y,mid+1,r);
}
int main(){
    //setIO("input"); 
    scanf("%d%d",&n,&Q);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
            mat[++idx].x=i,mat[idx].y=j;
            scanf("%d",&mat[idx].w); 
        }
    sort(mat+1,mat+1+idx,cmp);
    for(int i=1;i<=Q;++i) 
        scanf("%d%d%d%d%d",&ask[i].a,&ask[i].b,&ask[i].c,&ask[i].d,&ask[i].k),q[i]=i; 
    solve(1,Q,1,idx); 
    for(int i=1;i<=Q;++i) printf("%d
",answer[i]);
    return 0; 
}

  

原文地址:https://www.cnblogs.com/guangheli/p/10262509.html