2018.10.02 bzoj2738: 矩阵乘法(整体二分)

传送门
整体二分经典题。


直接整体二分第k大,用二维树状数组检验就行了。
代码:

#include<bits/stdc++.h>
#define N 505
#define Q 60005
using namespace std;
int n,m,a[N][N],val[N*N],bit[N][N],tot=0,ans[Q],cnt=0;
struct Query{int x1,y1,x2,y2,k,id;}q[Q],qtmp[Q];
struct Upd{int x,y,v;}upd[N*N];
inline int lowbit(int x){return x&-x;}
inline void update(int x,int y,int v){for(int i=x;i<=n;i+=lowbit(i))for(int j=y;j<=n;j+=lowbit(j))bit[i][j]+=v;}
inline int query(int x,int y){int ret=0;for(int i=x;i;i-=lowbit(i))for(int j=y;j;j-=lowbit(j))ret+=bit[i][j];return ret;}
inline void solve(int l,int r,int ql,int qr,int vl,int vr){
	if(l>r)return;
	if(ql==qr){
		for(int i=l;i<=r;++i)ans[q[i].id]=val[ql];
		return;
	}
	int mid=ql+qr>>1,hd=l-1,tl=r+1,vmid;
	for(int i=vl;i<=vr;++i){
		if(upd[i].v>mid)break;
		vmid=i,update(upd[i].x,upd[i].y,1);
	}
	for(int i=l;i<=r;++i){
		
		int tmp=query(q[i].x2,q[i].y2)+query(q[i].x1-1,q[i].y1-1)-query(q[i].x2,q[i].y1-1)-query(q[i].x1-1,q[i].y2);
		if(tmp>=q[i].k)qtmp[++hd]=q[i];
		else q[i].k-=tmp,qtmp[--tl]=q[i];
	}
	for(int i=vl;i<=vmid;++i)update(upd[i].x,upd[i].y,-1);
	for(int i=l;i<=r;++i)q[i]=qtmp[i];
	solve(l,hd,ql,mid,vl,vmid),solve(tl,r,mid+1,qr,vmid+1,vr);
}
inline bool cmp(Upd a,Upd b){return a.v<b.v;}
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)val[++tot]=a[i][j]=read();
	sort(val+1,val+tot+1),tot=unique(val+1,val+tot+1)-val-1;
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){
		a[i][j]=lower_bound(val+1,val+tot+1,a[i][j])-val;
		upd[++cnt]=(Upd){i,j,a[i][j]};
	}
	for(int i=1;i<=m;++i){
		int x1=read(),y1=read(),x2=read(),y2=read(),k=read();
		q[i]=(Query){x1,y1,x2,y2,k,i};
	}
	sort(upd+1,upd+cnt+1,cmp);
	solve(1,m,1,tot,1,cnt);
	for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值