1926: 粟粟的书架 前缀和+二分+主席树
题目大意:
http://www.lydsy.com/JudgeOnline/problem.php?id=1926
题解:
我们发现这道题其实是两问
第一问是对于 \(R, C\leq 200,M\leq 200,000\)
是在矩形上的询问
第二问是对于 \(R=1,C\leq 500,000,M\leq 20,000\)
是在序列上的询问
所以我们写两个程序即可
首先我们来解决序列上的问题:
很明显我们在主席树上二分查找即可.\(O(mlogn)\)可做
然后我们来解决在矩形上的问题:
很明显我们写个二维差分主席树就好了啦
我们发现这个子任务的特点是R,C的范围很小所以我们考虑预处理
我们可以预处理出\(f[i][j][k]\)表示在二维前缀和\((i,j)\)中
大于等于\(k\)的数的和,这样我们就可以二分啦!
同时为了统计答案我们还要处理出\(g[i][j][k]\)表示>=k的数的个数
然后这道题就华丽丽地解决啦
我们还有一个问题!
对于序列:2 2 2 2我们取多少才能达到高度\(2\),很明显取1个
但是程序会输出4
这个东西再二分一下还应该删除多少个不久好了吗。。。
竟然1A了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
int n,m,q;
namespace work1{
const int maxn = 201;
int a[maxn][maxn];
int f[201][201][1001];
int g[201][201][1001];
int lim = 0,x1,y1,x2,y2;
inline int calc_f(int k){
return f[x2][y2][k] - f[x1-1][y2][k] - f[x2][y1-1][k] + f[x1-1][y1-1][k];
}
inline int calc_g(int k){
return g[x2][y2][k] - g[x1-1][y2][k] - g[x2][y1-1][k] + g[x1-1][y1-1][k];
}
int main(){
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
read(a[i][j]);
lim = max(lim,a[i][j]);
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=1;k<=lim;++k){
f[i][j][k] = f[i-1][j][k] + f[i][j-1][k] - f[i-1][j-1][k];
g[i][j][k] = g[i-1][j][k] + g[i][j-1][k] - g[i-1][j-1][k];
}
for(int k=1;k<=a[i][j];++k){
f[i][j][k] += a[i][j];
g[i][j][k]++;
}
}
}
while(q--){
read(x1);read(y1);read(x2);read(y2);
int h;read(h);
int l = 1,r = lim,ans = -1;
while(l <= r){
int mid = (l+r) >> 1;
if(calc_f(mid) >= h) ans = mid,l = mid+1;
else r = mid-1;
}if(ans == -1) puts("Poor QLW");
else{
int x = calc_f(ans) - calc_f(ans+1);x /= ans;
int y = calc_g(ans);
int z = calc_f(ans);
l = 0,r = x;x = 0;
while(l <= r){
int mid = (l+r) >> 1;
if(z - mid*ans >= h) x = mid,l = mid+1;
else r = mid-1;
}y -= x;
printf("%d\n",y);
}
}
return 0;
}
}
namespace work2{
const int maxn = 500010;
typedef pair<int,int> pa;
struct Node{
Node *ch[2];
int sum,num;
}*null;
inline void init(){
null = new Node;
null->ch[0] = null->ch[1] = null;
null->sum = null->num = 0;
}
Node *rt[maxn];
inline Node* insert(Node *rt,int l,int r,int val){
Node *p = new Node();(*p) = (*rt);
if(l == r){
p->sum += val;
p->num ++ ;
return p;
}int mid = (l+r) >> 1;
if(val <= mid) p->ch[0] = insert(rt->ch[0],l,mid,val);
else p->ch[1] = insert(rt->ch[1],mid+1,r,val);
p->sum = p->ch[0]->sum + p->ch[1]->sum;
p->num = p->ch[0]->num + p->ch[1]->num;
return p;
}int pos = -1,cnt = -1;
inline pa query(Node *x,Node *y,int l,int r,int h){
if(l == r){
pos = l;cnt = y->num - x->num;
return make_pair(y->sum - x->sum,y->num - x->num);
}
int mid = (l+r) >> 1,sum = y->ch[1]->sum - x->ch[1]->sum;
if(sum < h){
pa tmp = query(x->ch[0],y->ch[0],l,mid,h-sum);
tmp.first += y->ch[1]->sum - x->ch[1]->sum;
tmp.second += (y->ch[1]->num - x->ch[1]->num);
return tmp;
}else return query(x->ch[1],y->ch[1],mid+1,r,h);
}
int main(){
init();n = m;rt[0] = null;
for(int i=1,x;i<=n;++i){
read(x);
rt[i] = insert(rt[i-1],1,1000,x);
}
while(q--){
int s,t;read(s);read(s);read(t);read(t);
int h;read(h);
pa x = query(rt[s-1],rt[t],1,1000,h);
if(x.first < h){puts("Poor QLW");continue;}
int l = 0,r = cnt,y = 0;
while(l <= r){
int mid = (l+r) >> 1;
if(x.first - mid*pos >= h) y = mid,l = mid+1;
else r = mid-1;
}
printf("%d\n",x.second - y);
}
return 0;
}
}
int main(){
read(n);read(m);read(q);
if(n != 1) work1::main();
else work2::main();
getchar();getchar();
return 0;
}
不得不说当时我开数组的时候浑身难受
一两个数组就100多MB下去了...
人就像命运下的蝼蚁,谁也无法操控自己的人生.