P2468 [SDOI2010]粟粟的书架

题目

P2468 [SDOI2010]粟粟的书架

我*做个**题目花了一个小时??

奔着主席树标签来的,\(n=1\)裸的主席树,\(n,m≤200\)裸的容斥(dalao们也可以去打一遍二维主席树)

容斥打了三遍才过,主席树查询竟然先去查询较小值??今天状态不好o(╥﹏╥)o

做法

\(n,m≤200\)是经典的容斥,大家应该都见过吧,预处理\(num_{i,j,k}\)为前\(i\)\(j\)\(≥k\)的个数,同理\(sum_{i,j,k}\)为前缀
剩下的是二分也不用多说了\(O(qlog max\{a_i\})\)

\(n=1\)这部分卡容斥的空间,主席树预处理值域区间个数及和\(O(qlog max\{a_i\})\)

My complete code

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef int LL;
const int inf=2000000001;
//const int maxn=2000000;
inline LL Read(){
	LL x(0),f(1);char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
LL n,m,q,Mi=inf,Mx=-inf,nod;
LL sum[209][209][1009],num[209][209][1009],a[209][209],b[500009],root[500009];
struct Tree{
	LL son[2],size,sum;
}T[20000009];
void Update(LL &now,LL pre,LL l,LL r,LL c){
	now=++nod;
	T[now].size=T[pre].size+1;
	T[now].sum=T[pre].sum+c;
	if(l==r)
	    return;
	LL mid(l+r>>1);
	if(c<=mid){
	    Update(T[now].son[0],T[pre].son[0],l,mid,c);
	    T[now].son[1]=T[pre].son[1];
	}else{
		Update(T[now].son[1],T[pre].son[1],mid+1,r,c);
	    T[now].son[0]=T[pre].son[0];
	}
}
LL Query(LL now,LL pre,LL l,LL r,LL val){
	if(l==r){
		return ceil((double)val/l);
	}
	LL mid(l+r>>1),ret=T[T[now].son[1]].sum-T[T[pre].son[1]].sum;
	if(ret>=val)
	    return Query(T[now].son[1],T[pre].son[1],mid+1,r,val);
	else
	    return (T[T[now].son[1]].size-T[T[pre].son[1]].size)+
		        Query(T[now].son[0],T[pre].son[0],l,mid,val-ret);
}
int main(){
	n=Read(),m=Read(),q=Read();
	if(n==1){
		for(LL i=1;i<=m;++i){
			LL now(Read());
			Mi=min(Mi,now),Mx=max(Mx,now);
			b[i]=b[i-1]+now;
		}
		for(LL i=1;i<=m;++i)
			Update(root[i],root[i-1],Mi,Mx,b[i]-b[i-1]);
		while(q--){
			LL xl(Read()),l(Read()),xr(Read()),r(Read()),x(Read());
			if(b[r]-b[l-1]<x){
				printf("Poor QLW\n");
				continue;
			}
			printf("%d\n",Query(root[r],root[l-1],Mi,Mx,x));
		}
	}else{
		for(LL i=1;i<=n;++i){
			for(LL j=1;j<=m;++j){
			    a[i][j]=Read();
			    Mi=min(Mi,a[i][j]),Mx=max(Mx,a[i][j]);
			}
		}
		for(LL i=1;i<=n;++i){
			for(LL j=1;j<=m;++j){
				for(LL k=Mx;k>=Mi;--k){
					num[i][j][k]=(num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k])+(a[i][j]>=k?1:0);
					sum[i][j][k]=(sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k])+(a[i][j]>=k?a[i][j]:0);
				}
			}
		}
		while(q--){
			LL xl(Read()),yl(Read()),xr(Read()),yr(Read()),x(Read()),ret,ans(0);
			LL l=Mi,r=Mx;
			if((sum[xr][yr][l]-sum[xr][yl-1][l]-sum[xl-1][yr][l]+sum[xl-1][yl-1][l])<x){
				printf("Poor QLW\n");
				continue;
			}
			while(l<=r){
				LL mid(l+r>>1);
				if((sum[xr][yr][mid]-sum[xr][yl-1][mid]-sum[xl-1][yr][mid]+sum[xl-1][yl-1][mid])>=x){
					ret=mid;
					l=mid+1;
				}else
				    r=mid-1;
			}
			++ret;
			x-=(sum[xr][yr][ret]-sum[xr][yl-1][ret]-sum[xl-1][yr][ret]+sum[xl-1][yl-1][ret]);
			ans+=(num[xr][yr][ret]-num[xr][yl-1][ret]-num[xl-1][yr][ret]+num[xl-1][yl-1][ret]);
			ans+=ceil((double)x/(ret-1));
			printf("%d\n",ans);
		}
	}
	return 0;
}
posted @ 2019-01-23 11:06  y2823774827y  阅读(122)  评论(0编辑  收藏  举报