# bzoj1926: [Sdoi2010]粟粟的书架

0.5倍经验orz……

$num[i][j][k]表示(1,1)到(i,j)中比大于等于k的数有几个$
$sum[i][j][k]表示(1,1)到(i,j)中比大于等于k的数的总和$

ps：主席树查询时应优先挑选高度更高的书，原因应该不用解释

  1 // luogu-judger-enable-o2
2 //minamoto
3 #include<bits/stdc++.h>
4 using namespace std;
6 char buf[1<<21],*p1=buf,*p2=buf;
7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
9     #define num ch-'0'
10     char ch;bool flag=0;int res;
11     while(!isdigit(ch=getc()))
12     (ch=='-')&&(flag=true);
13     for(res=num;isdigit(ch=getc());res=res*10+num);
14     (flag)&&(res=-res);
15     #undef num
16     return res;
17 }
18 int n,m,q;
19 namespace solve1{
20     #define N 205
21     int a[N][N],num[N][N][1005],sum[N][N][1005];
22     int mx=0;
23     int getsum(int a,int b,int c,int d,int h){
24         return sum[c][d][h]-sum[c][b][h]-sum[a][d][h]+sum[a][b][h];
25     }
26     int getnum(int a,int b,int c,int d,int h){
27         return num[c][d][h]-num[c][b][h]-num[a][d][h]+num[a][b][h];
28     }
29     int getans(int a,int b,int c,int d,int k,int need){
30         int res=getnum(a,b,c,d,k+1);
31         need-=getsum(a,b,c,d,k+1);
32         if(need>=0){
33             int num=need/k;
34             res+=num;
35             need-=num*k;
36             if(need>0) ++res,need-=k;
37         }
38         return res;
39     }
40     bool check(int a,int b,int c,int d,int mid,int h){
41         return getsum(a,b,c,d,mid)>h?1:0;
42     }
43     void main(){
44         for(int i=1;i<=n;++i)
45         for(int j=1;j<=m;++j)
47         for(int k=0;k<=mx;++k)
48         for(int i=1;i<=n;++i)
49         for(int j=1;j<=m;++j){
50             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);
51             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);
52         }
53         while(q--){
54             int a,b,c,d,h;
56             --a,--b;
57             if(getsum(a,b,c,d,0)<h){
58                 puts("Poor QLW");continue;
59             }
60             int l=1,r=mx,ans=0;
61             while(l<=r){
62                 int mid=(l+r)>>1;
63                 if(check(a,b,c,d,mid,h)) ans=mid,l=mid+1;
64                 else r=mid-1;
65             }
66             if(!ans) ans=1;
67             printf("%d\n",getans(a,b,c,d,ans,h));
68         }
69     }
70     #undef N
71 }
72 namespace solve2{
73     #define N 500005
74     int sum[N<<4],L[N<<4],R[N<<4],sz[N<<4];
75     int rt[N];
76     int mx=0,cnt=0;
77     void update(int last,int &now,int l,int r,int x){
78         sz[now=++cnt]=sz[last]+1,sum[now]=sum[last];
79         if(l==r){sum[now]+=x;return;}
80         int mid=(l+r)>>1;
81         if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);
82         else L[now]=L[last],update(R[last],R[now],mid+1,r,x);
83         sum[now]=sum[L[now]]+sum[R[now]];
84     }
85     int query(int u,int v,int l,int r,int k){
86         if(sz[v]-sz[u]<=k) return sum[v]-sum[u];
87         if(l==r) return (sum[v]-sum[u])/(sz[v]-sz[u])*k;
88         int mid=(l+r)>>1;
89         if(sz[R[v]]-sz[R[u]]>=k) return query(R[u],R[v],mid+1,r,k);
90         else return query(L[u],L[v],l,mid,k-(sz[R[v]]-sz[R[u]]))+sum[R[v]]-sum[R[u]];
91     }
92     void main(){
93         mx=1000;
94         for(int i=1;i<=m;++i){
96             update(rt[i-1],rt[i],1,mx,x);
97         }
98         while(q--){
100             --b;
101             int l=1,r=d-b+1;
102             while(l<r){
103                 int mid=(l+r)>>1;
104                 if(query(rt[b],rt[d],1,mx,mid)>=h) r=mid;
105                 else l=mid+1;
106             }
107             if(r==d-b+1) puts("Poor QLW");
108             else printf("%d\n",l);
109         }
110     }
111 }
112 int main(){
113     //freopen("testdata.in","r",stdin);
118 }