【粟粟的书架】【题解】


【粟粟的书架】【题解】

题目传送门

Solution

数据范围分为两部分,第一部分二分,第二部分主席树。
其实一开始没想到第一部分怎么做,因为我原本想直接二分排名,但前缀和没法维护排名。

但是实际上二分选取的数的最小值一样能做,而且可以容易用前缀和维护。(可以记住这个trick)

第二部分就是主席树的模板了,把区间看做两个前缀主席树相减,如果右子树够用就递归到右子树,否则累计上右子树答案,再递归到左子树。

Code

#include
using namespace std;

inline int read()
{
	register int x=0,w=1;
	register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
const int N=210,M=5e5+10,W=1010;
struct node{
	int ls,rs,sum,cnt;
}t[M*15];
int sum[N][N][W],cnt[N][N][W];
int tot,a[M],rt[M];
int n,m,T;
int build(int l,int r)
{
	int p=++tot;
	if(l==r) return p;
	int mid=l+r>>1;
	t[p].ls=build(l,mid);
	t[p].rs=build(mid+1,r);
	return p;
}
void pushup(int x)
{
	t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
	t[x].cnt=t[t[x].ls].cnt+t[t[x].rs].cnt;
}
int insert(int x,int l,int r,int pos)
{
	int p=++tot;
	t[p]=t[x];
	if(l==r){
		t[p].cnt++;
		t[p].sum+=l;
		return p;
	}
	int mid=l+r>>1;
	if(pos<=mid) t[p].ls=insert(t[p].ls,l,mid,pos);
	else t[p].rs=insert(t[p].rs,mid+1,r,pos);
	pushup(p);
	return p;
}
int query(int p,int q,int l,int r,int val)
{
	if(l==r){
		if(val%l==0) return val/l;
		return val/l+1;
	}
	int mid=l+r>>1;
	int rsum=t[t[q].rs].sum-t[t[p].rs].sum,rcnt=t[t[q].rs].cnt-t[t[p].rs].cnt;
//	if(val==rsum) return rcnt;
	if(val<=rsum) return query(t[p].rs,t[q].rs,mid+1,r,val);
	return query(t[p].ls,t[q].ls,l,mid,val-rsum)+rcnt;
}
inline void write(int x)
{
	if(x<0) {putchar('-');x=~(x-1);}
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
int main()
{
    n=read();m=read();T=read();
    if(n==1)
    {
    	int maxn=0;
    	for(int i=1;i<=m;++i) {
    		a[i]=read();
    		maxn=max(maxn,a[i]);
		}
    	rt[0]=build(1,maxn);
    	for(int i=1;i<=m;++i){
    		rt[i]=insert(rt[i-1],1,maxn,a[i]);
		}
		for(int i=1;i<=T;++i)
		{
			int x[3],y[3];
			x[1]=read(),y[1]=read();
			x[2]=read(),y[2]=read();
			int h=read();
			if(t[rt[y[2]]].sum-t[rt[y[1]-1]].sum>1;
					if(sum[x[2]][y[2]][mid]-sum[x[1]-1][y[2]][mid]-sum[x[2]][y[1]-1][mid]+sum[x[1]-1][y[1]-1][mid]>=h) l=mid;
					else r=mid;
				}
				write(cnt[x[2]][y[2]][l+1]-cnt[x[1]-1][y[2]][l+1]-cnt[x[2]][y[1]-1][l+1]+cnt[x[1]-1][y[1]-1][l+1]+(int)ceil((h-(sum[x[2]][y[2]][l+1]-sum[x[1]-1][y[2]][l+1]-sum[x[2]][y[1]-1][l+1]+sum[x[1]-1][y[1]-1][l+1]))*1.0/l*1.0));
			    puts("");
			}
		}
	}
	return 0;
}