bzoj1926: [Sdoi2010]粟粟的书架
题目链接
题解
大佬好强
看了看数据范围,不是很明白为什么明明两道题却硬要挤在一道题里
0.5倍经验orz……
前一半的数据$R,C<=200$
前缀和+二分
$num[i][j][k]表示(1,1)到(i,j)中比大于等于k的数有几个$
$sum[i][j][k]表示(1,1)到(i,j)中比大于等于k的数的总和$
二分找k+1,对k直接暴力填
后一半的数据就是个序列
直接开个主席树
二分一下取多少本书
然后直接树上跑一跑就行
ps:主席树查询时应优先挑选高度更高的书,原因应该不用解释
1 // luogu-judger-enable-o2 2 //minamoto 3 #include<bits/stdc++.h> 4 using namespace std; 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 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;} 8 inline int read(){ 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) 46 cmax(mx,a[i][j]=read()); 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; 55 a=read(),b=read(),c=read(),d=read(),h=read(); 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){ 95 int x=read(); 96 update(rt[i-1],rt[i],1,mx,x); 97 } 98 while(q--){ 99 int a=read(),b=read(),c=read(),d=read(),h=read(); 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); 114 n=read(),m=read(),q=read(); 115 if(n!=1) solve1::main(); 116 else solve2::main(); 117 return 0; 118 }
深深地明白自己的弱小