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;
}