[BZOJ2738]矩阵乘法(整体二分+二维树状数组)

整体二分+二维树状数组。

好题啊!写了一个来小时。

一看这道题,主席树不会搞,只能用离线的做法了。

整体二分真是个好东西,啥都可以搞,尤其是区间第 \(k\) 大这种东西。

我们二分答案,然后用二维树状数组实现 \(\log^2 n\) 的单点修改,时间复杂度 \(O(q\log^2 n\log 10^9)\)

\(Code\ Below:\)

#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
#define id(x,y) (((x)-1)*n+(y)) 
using namespace std;
const int maxn=300000+10;
const int lim=1e9;
int n,m,c[510][510],ans[maxn];
 
struct Element{
    int x,y,k;
}e[maxn],e1[maxn],e2[maxn];
 
bool cmp(Element a,Element b){
    return a.k<b.k;
}
 
struct Query{
    int x1,y1,x2,y2,k,id;
}q[maxn],q1[maxn],q2[maxn];
 
inline int read(){
    register int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return (f==1)?x:-x;
}
 
inline void add(int x,int y,int z){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=n;j+=lowbit(j)) c[i][j]+=z;
}
 
inline int sum(int x,int y){
    int ans=0;
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j)) ans+=c[i][j];
    return ans;
}
 
void solve(int L,int R,int Le,int Ri,int l,int r){
    if(L>R||Le>Ri) return ;
    if(l==r){
        for(int i=Le;i<=Ri;i++) ans[q[i].id]=l;
        return ;
    }
    int mid=(l+r)>>1,cnt1=0,cnt2=0,tot1=0,tot2=0,val;
    for(int i=L;i<=R;i++){
        if(e[i].k<=mid) add(e[i].x,e[i].y,1),e1[++cnt1]=e[i];
        else e2[++cnt2]=e[i];
    }
    for(int i=1;i<=cnt1;i++) e[L+i-1]=e1[i];
    for(int i=1;i<=cnt2;i++) e[L+i+cnt1-1]=e2[i];
    for(int i=Le;i<=Ri;i++){
        val=sum(q[i].x2,q[i].y2)-sum(q[i].x1-1,q[i].y2)-sum(q[i].x2,q[i].y1-1)+sum(q[i].x1-1,q[i].y1-1);
        if(val>=q[i].k) q1[++tot1]=q[i];
        else q[i].k-=val,q2[++tot2]=q[i];
    }
    for(int i=L;i<=L+cnt1-1;i++) add(e[i].x,e[i].y,-1);
    for(int i=1;i<=tot1;i++) q[Le+i-1]=q1[i];
    for(int i=1;i<=tot2;i++) q[Le+i+tot1-1]=q2[i];
    solve(L,L+cnt1-1,Le,Le+tot1-1,l,mid);
    solve(L+cnt1,R,Le+tot1,Ri,mid+1,r);
}
 
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) e[id(i,j)].x=i,e[id(i,j)].y=j,e[id(i,j)].k=read();
    sort(e+1,e+n*n+1,cmp);
    for(int i=1;i<=m;i++) q[i].x1=read(),q[i].y1=read(),q[i].x2=read(),q[i].y2=read(),q[i].k=read(),q[i].id=i;
    solve(1,n*n,1,m,0,lim);
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-12-29 22:02  Owen_codeisking  阅读(163)  评论(0编辑  收藏  举报