zoukankan      html  css  js  c++  java
  • [SDOI2010]粟粟的书架 [主席树]

    [SDOI2010]粟粟的书架

    考虑暴力怎么做 显然是提取出来 (x2-x1+1)*(y2-y1+1) 个数字拿出来 然后从大到小排序

    然后就可以按次取数了…

    然而接下来看数据范围

    (50\% r,cleq 200)
    (50\% r=1,cleq 5*10^5)
    值域 (in [1,1000])
    对于前 50% 可以用个前缀和搞定…
    (sum_{i,j,k}) 为 大于 k 的前缀和
    (num_{i,j,k}) 为 大于 k 的前缀和数量
    然后愉快的二分?

    另外50%主席树乱草
    看准值域直接二分

    前面的复杂度是 (O(rc log max{a_i}))
    后面的复杂度是 (O(rc log^2 max{a_i}))

    直接考虑当前有多少…
    还有一个显而易见的性质
    如果当前最优解为(ans) 那么肯定存在数字(ans) 以及 (sum-h < cnt*ans)
    算出来除一下就可以了我也不知道为什么我脑抽写了一直减…还查询了个数…

    
    #include <bits/stdc++.h>
    // #define int long long
    #define rep(a , b , c) for(register int a = b ; a <= c ; ++ a)
    #define Rep(a , b , c) for(register int a = b ; a >= c ; -- a)
    #define go(u) for(int i = G.head[u] , v = G.to[i] , w = e[i].dis ; i ; v = G.to[i = G.nxt[i]] , w = e[i].dis)
    
    using namespace std ;
    using ll = long long ;
    using pii = pair < int , int > ;
    using vi = vector < int > ;
    
    inline int read() {
    	register int x = 0 ;
    	bool f = 1 ;
    	register char c = getchar() ;
    	while(c < 48 || c > 57) {
    		if(c == '-') f = 0 ;
    		c = getchar() ;
    	}
    	while(c > 47 && c < 58) {
    		x = (x << 1) + (x << 3) + (c & 15) ;
    		c = getchar() ;
    	}
    	return f ? x : -x ;
    }
    
    template <class T> inline void print(T x , char c = '
    ') {
    	static char st[100] ;
    	int stp = 0 ;
    	if(! x) {
    		putchar('0') ;
    	}
    	if(x < 0) {
    		x = -x ;
    		putchar('-') ;
    	}
    	while(x) {
    		st[++ stp] = x % 10 ^ 48 ;
    		x /= 10 ;
    	}
    	while(stp) {
    		putchar(st[stp --]) ;
    	}
    	putchar(c) ;
    }
    
    template <class T> void cmax(T & x , T y) {
    	x < y ? x = y : 0 ;
    }
    template <class T> void cmin(T & x , T y) {
    	x > y ? x = y : 0 ;
    }
    
    const int _N = 1e6 + 10 ;
    struct Group {
    	int head[_N] , nxt[_N << 1] , to[_N] , dis[_N] , cnt = 1 ;
    	Group () {
    		memset(head , 0 , sizeof(head)) ;
    	}
    	void add(int u , int v , int w = 1) {
    		nxt[++ cnt] = head[u] ;
    		to[cnt] = v ;
    		dis[cnt] = w ;
    		head[u] = cnt ;
    	}
    } ;
    
    const int N = 1e5 + 10  ;
    typedef int arr[N] ;
    int r , c , m ;
    const int N1 = 233 ;
    const int N2 = 5e5 + 10 ;
    int len = 0 ;
    int a[N1][N1] ;
    //struct Small_Tree {
    //	int rt[N1] , cnt = 0 , ls[N1 << 5] , rs[N1 << 5] , sum[N1 << 5] , sz[N1 << 5] ;
    //	void upd(int pre , int & p , int l , int r , int val) {
    //		ls[p = ++ cnt] = ls[pre] , rs[p] = rs[pre] ;
    //		sum[p] = sum[pre] + val , sz[p] = sz[pre] + 1 ;
    //		if(l == r) return ;
    //		int mid = l + r >> 1 ;
    //		val <= mid ? upd(ls[pre] , ls[p] , l , mid , val) : upd(rs[pre] , rs[p] , mid + 1 , r , val) ;
    //	}
    //	int query(int a , int b , int pre , int p , int l , int r) {
    //		if(a <= l && r <= b) return sum[p] - sum[pre] ;
    //		int mid = l + r >> 1 , ans = 0 ;
    //		if(a <= mid) ans += query(a , b , ls[pre] , ls[p] , l , mid) ;
    //		if(b > mid) ans += query(a , b , rs[pre] , rs[p] , mid + 1 , r) ;
    //		return ans ;
    //	}
    //	int query_sz(int a , int b , int pre , int p , int l , int r) {
    //		if(a <= l && r <= b) return sz[p] - sz[pre] ;
    //		int mid = l + r >> 1 ;
    //		int ans = 0 ;
    //		if(a <= mid) ans += query_sz(a , b , ls[pre] , ls[p] , l , mid) ;
    //		if(b > mid) ans += query_sz(a , b , rs[pre] , rs[p] , mid + 1 , r) ;
    //		return ans ;
    //	}
    //} t[233] ;
    //void solve1() {
    //	rep(i , 1 , r)	rep(j , 1 , c) a[i][j] = read() ;
    //	rep(i , 1 , r)  rep(j , 1 , c) cmax(len , a[i][j]) ;
    //	rep(i , 1 , r)  rep(j , 1 , c) t[i].upd(t[i].rt[j - 1] , t[i].rt[j] , 1 , len , a[i][j]) ;
    //	while(m --) {
    //		int x1 = read() , y1 = read() , x2 = read() , y2 = read() , h = read() ;
    //		int l = 0 , r = len + 1 ;
    //		int ans = -1 ;
    //		while(l <= r) {
    //			int mid = l + r >> 1 , sum = 0 ;
    //			rep(i , x1 , x2) sum += t[i].query(mid , len , t[i].rt[y1 - 1] , t[i].rt[y2] , 1 , len) ;
    //			if(sum >= h) {
    //				ans = mid ;
    //				l = mid + 1 ;
    //			}
    //			else r = mid - 1 ;
    //		}
    //		if(ans == -1) {
    //			puts("Poor QLW") ;
    //			continue ;
    //		}
    //		int tot = 0 , onlytot = 0 , sum = 0 ;
    //		rep(i , x1 , x2) sum += t[i].query(ans , len , t[i].rt[y1 - 1] , t[i].rt[y2] , 1 , len) ;
    //		rep(i , x1 , x2) tot += t[i].query_sz(ans , len , t[i].rt[y1 - 1] , t[i].rt[y2] , 1 , len) ;
    //		rep(i , x1 , x2) onlytot += t[i].query_sz(ans , ans , t[i].rt[y1 - 1] , t[i].rt[y2] , 1 , len) ;
    //		int cnt = 0 ;
    //		while(sum - ans >= h && cnt < onlytot) {
    //			sum -= ans ;
    //			cnt ++ ;
    //		}
    //		print(tot - cnt) ;
    //	}
    //}
    
    int val[N1][N1][1005] ;
    int num[N1][N1][1005] ;
    int get_val(int a1 , int b1 , int a2 , int b2 , int k) {
    	return val[a2][b2][k] - val[a1 - 1][b2][k] - val[a2][b1 - 1][k] + val[a1 - 1][b1 - 1][k] ;
    }
    int get_num(int a1 , int b1 , int a2 , int b2 , int k) {
    	return num[a2][b2][k] - num[a1 - 1][b2][k] - num[a2][b1 - 1][k] + num[a1 - 1][b1 - 1][k] ;
    }
    void solve1() {
    	rep(i , 1 , r) rep(j , 1 , c) {
    		a[i][j] = read() ;
    		cmax(len , a[i][j]) ;
    	}
    	rep(k , 0 , len) {
    		rep(i , 1 , r) {
    			rep(j , 1  , c) {
    				val[i][j][k] = val[i - 1][j][k] + val[i][j - 1][k] - val[i - 1][j - 1][k] + (a[i][j] >= k ? a[i][j] : 0) ;
    				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) ;
    			}
    		}
    	}
      while(m --) {
      	int a1 = read() , b1 = read() , a2 = read() , b2 = read() , h = read() ;
      	if(get_val(a1 , b1 , a2 , b2 , 0) < h) {
      		puts("Poor QLW") ;
      		continue ;
    		}
    		int l = 0 , r = len + 1 , ans = -1 ;
    		while(l <= r) {
    			int mid = l + r >> 1 ;
    			if(get_val(a1 , b1 , a2 , b2 , mid) >= h) {
    				ans = mid ;
    				l = mid + 1 ;
    			}
    			else r = mid - 1 ;
    		}
    		if(ans == -1) {
    			puts("Poor QLW") ;
    			continue ;
    		}
    		print(get_num(a1 , b1 , a2 , b2 , ans) - ((get_val(a1 , b1 , a2 , b2 , ans) - h) / ans)) ;
    	}
    }
    struct Big_Tree {
    	int rt[N2] , cnt = 0 ;
    	int ls[N2 << 5] , rs[N2 << 5] , sum[N2 << 5] , sz[N2 << 5] ;
    	void upd(int pre , int & p , int l , int r , int val) {
    		ls[p = ++ cnt] = ls[pre] ;
    		rs[p] = rs[pre] ;
    		sum[p] = sum[pre] + val ;
    		sz[p] = sz[pre] + 1 ;
    		if(l == r) return ;
    		int mid = l + r >> 1 ;
    		val <= mid ? upd(ls[pre] , ls[p] , l , mid , val) : upd(rs[pre] , rs[p] , mid + 1 , r , val) ;
    	}
    	int query(int a , int b , int pre , int p , int l , int r) {
    		if(a <= l && r <= b) return sum[p] - sum[pre] ;
    		int mid = l + r >> 1 ;
    		int ans = 0 ;
    		if(a <= mid) ans += query(a , b , ls[pre] , ls[p] , l , mid) ;
    		if(b > mid) ans += query(a , b , rs[pre] , rs[p] , mid + 1 , r) ;
    		return ans ;
    	}
    	int query_sz(int a , int b , int pre , int p , int l , int r) {
    		if(a <= l && r <= b) return sz[p] - sz[pre] ;
    		int mid = l + r >> 1 ;
    		int ans = 0 ;
    		if(a <= mid) ans += query_sz(a , b , ls[pre] , ls[p] , l , mid) ;
    		if(b > mid) ans += query_sz(a , b , rs[pre] , rs[p] , mid + 1 , r) ;
    		return ans ;
    	}
    } bigt ;
    vi v ;
    void solve2() {
    	v.resize(c + 1) ;
    	rep(i , 1 , c) v[i] = read() ;
    	rep(i , 1 , c) cmax(len , v[i]) ;
    	rep(i , 1 , c) bigt.upd(bigt.rt[i - 1] , bigt.rt[i] , 1 , len , v[i]) ;
    	while(m --) {
    		int x1 = read() , y1 = read() , x2 = read() , y2 = read() , h = read() ;
    		int l = 0 , r = len + 1 , ans = -1 ;
    		while(l <= r) {
    			int mid = l + r >> 1 ;
    			int sum = bigt.query(mid , len , bigt.rt[y1 - 1] , bigt.rt[y2] , 1 , len) ;
    			if(sum >= h) {
    				ans = mid ;
    				l = mid + 1 ;
    			}
    			else r = mid - 1 ;
    		}
    		if(ans == -1) {
    			puts("Poor QLW") ;
    			continue ;
    		}
    		int tot = 0 , onlytot = 0 , sum = 0 ;
    		sum = bigt.query(ans , len , bigt.rt[y1 - 1] , bigt.rt[y2] , 1 , len) ;
    		tot = bigt.query_sz(ans , len , bigt.rt[y1 - 1] , bigt.rt[y2] , 1 , len) ;
    		onlytot = bigt.query_sz(ans , ans , bigt.rt[y1 - 1] , bigt.rt[y2] , 1 , len) ;
    		int cnt = 0 ;
    		while(sum - ans >= h && cnt < onlytot) { sum -= ans ; cnt ++ ; }
    		print(tot - cnt) ;
    	}
    }
    signed main() {
    	r = read() ; c = read() ; m = read() ;
    	if(r ^ 1) solve1() ;
    	else solve2() ;
    	return 0 ;
    }
    
  • 相关阅读:
    快速幂
    Oracle悲观锁和乐观锁
    UTL_RAW的问题?
    Linux操作系统下关于Top命令的参数详解
    存储过程与函数
    网站前端优化一些小经验
    Java获取各种常用时间方法2
    Pro CSS Techniques 读书笔记(六)
    Java获取各种常用时间方法
    Oracle专用服务器与共享服务器的区别
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12016411.html
Copyright © 2011-2022 走看看