bzoj2738 矩阵乘法

题目链接:bzoj2738

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

【= =题目在逗我吧


题解:

整体二分

不过是不带修改的区间第k小的升级版。

改用二维树状数组维护就好了。

可能是我常数太大代码太丑?狂TLE,最后加了个读优卡过了。。。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 351000
#define N 600
#define inf 1e9

struct node
{
	int x1,x2,y1,y2,c,tg,ans;
}q[maxn];
int n,m,id[maxn],c[N][N];
int tol[maxn],tor[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int lowbit(int x){return x&(-x);}
void change(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 ret=0;
	for (int i=x;i>0;i-=lowbit(i))
	  for (int j=y;j>0;j-=lowbit(j))
	   ret+=c[i][j];
	return ret;
}
void solve(int head,int tail,int l,int r)
{
	if (head>tail) return;
	int lnum=0,rnum=0,i,mid=(l+r)>>1;
	if (l==r)
	{
		for (i=head;i<=tail;i++)
		  if (q[id[i]].tg==2) q[id[i]].ans=l;
		return;
	}
	for (i=head;i<=tail;i++)
	  if (q[id[i]].tg==1)
	  {
		  if (q[id[i]].c<=mid) tol[++lnum]=id[i],change(q[id[i]].x1,q[id[i]].y1,1);
		  else tor[++rnum]=id[i];
	  }else
	  {
		  int now=query(q[id[i]].x2,q[id[i]].y2)-query(q[id[i]].x2,q[id[i]].y1-1)-query(q[id[i]].x1-1,q[id[i]].y2)+query(q[id[i]].x1-1,q[id[i]].y1-1);
		  if (now>=q[id[i]].c) tol[++lnum]=id[i];
		  else q[id[i]].c-=now,tor[++rnum]=id[i];
	  }
	for (i=head;i<=tail;i++)
	  if (q[id[i]].tg==1 && q[id[i]].c<=mid) change(q[id[i]].x1,q[id[i]].y1,-1);
	for (i=0;i<lnum;i++) id[head+i]=tol[i+1];
	for (i=0;i<rnum;i++) id[head+i+lnum]=tor[i+1];
	solve(head,head+lnum-1,l,mid);
	solve(head+lnum,tail,mid+1,r);
}
int main()
{
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int i,j,x,t=0;
	// scanf("%d%d",&n,&m);
	n=read();m=read();
	for (i=1;i<=n;i++)
	 for (j=1;j<=n;j++)
	 {
		 id[++t]=t;x=read();
		 // scanf("%d",&x);
		 q[t].x1=i;q[t].y1=j;
		 q[t].c=x;q[t].tg=1;
	 }
	for (i=1;i<=m;i++)
	{
		id[++t]=t;
		q[t].x1=read();q[t].y1=read();
		q[t].x2=read();q[t].y2=read();
		// scanf("%d%d%d%d",&q[t].x1,&q[t].y1,&q[t].x2,&q[t].y2);
		q[t].c=read();// scanf("%d",&q[t].c);
		q[t].tg=2;q[t].ans=-1;
	}
	solve(1,t,0,inf);
	for (i=1;i<=t;i++) if (q[i].tg==2) printf("%d\n",q[i].ans);
	return 0;
}


posted @ 2017-01-16 11:03  OxQ  阅读(149)  评论(0编辑  收藏  举报