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下去了...

  • 相关阅读:
    PHP5中__call、__get、__set、__clone、__sleep、__wakeup的用法
    MyISAM InnoDB 区别
    Mozilla推荐的CSS书写顺序
    转:Javascript异步编程的4种方法
    从一个实例,看new FunctionName()的内部机制
    矩阵转置 O(1)空间
    不要将 Array、Object 等类型指定给 prototype
    javascript线程解释(setTimeout,setInterval你不知道的事)
    JS 中没有按地址(引用)传递,只有按值传递
    输入一个无符号整数,用最少的步骤将该数变为1
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6421039.html
Copyright © 2011-2022 走看看