P1527,JZOJ 2908【集训队互测 2012】矩阵乘法(mat)

D e s c r i p t i o n Description Description

无修子矩阵第 k k k

数据范围: n , m ≤ 500 n,m\leq 500 n,m500


S o l u t i o n Solution Solution

整体二分+二维树状数组当然你也可以大数据结构

s o l v e ( l , r , L , R ) solve(l,r,L,R) solve(l,r,L,R),表示在 [ l , r ] [l,r] [l,r]范围中,与操作 [ L , R ] [L,R] [L,R]有关(不一定对应原来的操作)

如果原矩阵的数 ≤ m i d \leq mid mid,就在二维树状数组对应位置+1,如果碰到询问操作,那么查询区间 [ q l , q r ] [ql,qr] [ql,qr]的值,相当于查询 [ l , m i d ] [l,mid] [l,mid]中树状数组的值,如果 ≤ k \leq k k,则答案在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r]中,此时把 k k k减去对应的个数【参照权值线段树】,否则答案就在左边,分治处理即可

时间复杂度: O ( n 2 l o g 2 n 2 ) O(n^2 log^2n^2) O(n2log2n2)【大概吧】


C o d e Code Code

#include
#include
#include
#define LL long long
using namespace std;int n,m,cnt;
inline LL read()
{
	LL f=0,d=1;char c; 
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
struct node{int x1,y1,x2,y2,k,id;}q[320011],q1[320010],q2[320011];
int ans[60010],c[501][501];
inline void add(int x,int y,int d)
{
	for(register int i=x;i<=n;i+=i&-i)
	 for(register int j=y;j<=n;j+=j&-j)
	  c[i][j]+=d;
	return;
}
inline int ask(int x,int y)
{
	if(!x||!y) return 0;
	int ans=0;
	for(register int i=x;i;i-=i&-i)
	 for(register int j=y;j;j-=j&-j)
	  ans+=c[i][j];
	return ans;
}
inline int sum(int x1,int y1,int x2,int y2){return ask(x2,y2)-ask(x2,y1-1)-ask(x1-1,y2)+ask(x1-1,y1-1);}
inline void solve(int l,int r,int L,int R) 
{
	if(L>R) return;
	if(l==r)
	{
		for(register int i=L;i<=R;i++) if(q[i].id) ans[q[i].id]=l;
		return;
	}
	int mid=l+r>>1,cnt1=0,cnt2=0;
	for(register int i=L;i<=R;i++)
	{
		if(q[i].id==0)
		{
			if(q[i].k<=mid) add(q[i].x1,q[i].y1,1),q1[++cnt1]=q[i];
			else q2[++cnt2]=q[i];
		}
		else
		{
			int x=sum(q[i].x1,q[i].y1,q[i].x2,q[i].y2);
			if(x>=q[i].k) q1[++cnt1]=q[i];
			else q[i].k-=x,q2[++cnt2]=q[i];
		}
	}
	for(register int i=1;i<=cnt1;i++) if(q1[i].id==0) add(q1[i].x1,q1[i].y1,-1);
	for(int i=L;i<=L+cnt1-1;i++) q[i]=q1[i-L+1];
    for(int i=L+cnt1;i<=R;i++) q[i]=q2[i-L-cnt1+1];
    solve(l,mid,L,L+cnt1-1);
    solve(mid+1,r,L+cnt1,R);
    return;
}
signed main()
{
	n=read();m=read();
	for(register int i=1;i<=n;i++)
	 for(register int j=1;j<=n;j++)
	  q[++cnt]=(node){i,j,0,0,read(),0};
	for(register int i=1;i<=m;i++)
	{
		q[++cnt].x1=read();q[cnt].y1=read();q[cnt].x2=read();q[cnt].y2=read();q[cnt].k=read();
		q[cnt].id=i;
	}
	solve(0,1e9,1,cnt);
	for(register int i=1;i<=m;i++) printf("%d\n",ans[i]);
}

你可能感兴趣的:(整体二分,二维树状数组)