zoukankan      html  css  js  c++  java
  • 1926: 粟粟的书架 前缀和+二分+主席树

    题目大意:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1926

    题解:

    我们发现这道题其实是两问
    第一问是对于 (R, Cleq 200,Mleq 200,000)
    是在矩形上的询问
    第二问是对于 (R=1,Cleq 500,000,Mleq 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
    ",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
    ",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下去了...

  • 相关阅读:
    NYOJ 625 笨蛋的难题(二)
    NYOJ 102 次方求模
    ZJU Least Common Multiple
    ZJUOJ 1073 Round and Round We Go
    NYOJ 709 异形卵
    HDU 1279 验证角谷猜想
    BNUOJ 1015 信息战(一)——加密程序
    HDU 1202 The calculation of GPA
    "蓝桥杯“基础练习:字母图形
    "蓝桥杯“基础练习:数列特征
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6421039.html
Copyright © 2011-2022 走看看