BZOJ 1926 [Sdoi2010]粟粟的书架

Posted ws_zzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1926 [Sdoi2010]粟粟的书架相关的知识,希望对你有一定的参考价值。

题解:

这是两道题

前50%:

发现p[i][j]很小,于是记录f[i][j][k]表示(1,1)~(i,j)这个子矩阵内>=k的书的总高度,g[i][j][k]记录本数

查询是二分答案就好了

后50%:

主席树,右子树够了就向右走,否则向左走

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m,T;

int PTsiz;
int root[500009];
struct PresidentTree{
	int ls,rs,d,sum;
}tree[10000009];
void BuildTree(int &now,int l,int r){
	now=++PTsiz;
	tree[now].d=tree[now].sum=0;
	if(l==r)return;
	int mid=(l+r)>>1;
	BuildTree(tree[now].ls,l,mid);
	BuildTree(tree[now].rs,mid+1,r);
}
void Updatapoint(int &now,int pre,int p,int x,int l,int r){
	now=++PTsiz;
	tree[now]=tree[pre];
	tree[now].d++;tree[now].sum+=x;
//	cout<<"shit"<<tree[now].l<<‘ ‘<<tree[now].r<<endl;
	if(l==r)return;
	
	int mid=(l+r)>>1;
	if(p<=mid)Updatapoint(tree[now].ls,tree[pre].ls,p,x,l,mid);
	else Updatapoint(tree[now].rs,tree[pre].rs,p,x,mid+1,r);
}
int a[500009];
int b[500009],nn;
int sum2[500009];
int Queryamount(int now,int pre,int tot,int l,int r){
	if(l==r){
		int x=b[l];
		if(tot%x==0)return tot/x;
		else return tot/x+1;
	}
	int s=tree[tree[now].rs].sum-tree[tree[pre].rs].sum;
	int d=tree[tree[now].rs].d-tree[tree[pre].rs].d;
//	printf("%d %d %d %d\n",b[tree[now].l],b[tree[now].r],d,s);
//	if(s==tot)return d;
	int mid=(l+r)>>1;
	if(s<tot)return d+Queryamount(tree[now].ls,tree[pre].ls,tot-s,l,mid);
	else return Queryamount(tree[now].rs,tree[pre].rs,tot,mid+1,r);
}

const int u=1000;
int f[209][209][u+10];//amount 
int g[209][209][u+10];//sum
int c[209][209];
int Getans(int x,int y,int xx,int yy,int s){
	int l=1,r=u,mid,ans=1;
	while(l<=r){
		mid=(l+r)>>1;
		int tmp=g[xx][yy][mid]-g[xx][y-1][mid]-g[x-1][yy][mid]+g[x-1][y-1][mid];
		if(tmp>=s){
			ans=mid;l=mid+1;
		}else{
			r=mid-1;
		}
	}
	int tmp=f[xx][yy][ans]-f[xx][y-1][ans]-f[x-1][yy][ans]+f[x-1][y-1][ans];
	int tmp2=g[xx][yy][ans]-g[xx][y-1][ans]-g[x-1][yy][ans]+g[x-1][y-1][ans];
	return tmp-(tmp2-s)/ans;
//	return tmp;
}

int Workans1(){
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			scanf("%d",&c[i][j]);
			for(int k=0;k<=u;++k){
				f[i][j][k]=f[i][j-1][k]+f[i-1][j][k]-f[i-1][j-1][k];
				g[i][j][k]=g[i][j-1][k]+g[i-1][j][k]-g[i-1][j-1][k];
				if(k<=c[i][j]){
					f[i][j][k]+=1;
					g[i][j][k]+=c[i][j];
				}
			}
		}
	}
	while(T--){
		int x,y,xx,yy,s;
		scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&s);
		int maxsum=g[xx][yy][0]-g[x-1][yy][0]-g[xx][y-1][0]+g[x-1][y-1][0];
		if(maxsum<s)printf("Poor QLW\n");
		else printf("%d\n",Getans(x,y,xx,yy,s));
	}
}

int Workans2(){
	for(int i=1;i<=m;++i){
		scanf("%d",&a[i]);b[i]=a[i];sum2[i]=a[i]+sum2[i-1];
	}
	sort(b+1,b+1+m);
	nn=unique(b+1,b+1+m)-b-1;
	
	BuildTree(root[0],1,nn);
	for(int i=1;i<=m;++i)Updatapoint(root[i],root[i-1],lower_bound(b+1,b+1+nn,a[i])-b,a[i],1,nn);
	while(T--){
		int x,y,xx,yy,s;
		scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&s);
		int tmp=Queryamount(root[yy],root[y-1],s,1,nn);
		if(sum2[yy]-sum2[y-1]>=s)printf("%d\n",tmp);
		else printf("Poor QLW\n");
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&T);
	if(n!=1)Workans1();
	else Workans2();
	return 0;
}

  

以上是关于BZOJ 1926 [Sdoi2010]粟粟的书架的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1926 [Sdoi2010]粟粟的书架

刷题BZOJ 1926 [Sdoi2010]粟粟的书架

AC日记——[Sdoi2010]粟粟的书架 bzoj 1926

BZOJ 1926 [Sdoi2010]粟粟的书架

BZOJ1926 [Sdoi2010]粟粟的书架 主席树 + 二分 + 前缀和

1926: [Sdoi2010]粟粟的书架