• Luogu P2468 [SDOI2010]粟粟的书架


    一道二合一的题目。两部分思维难度都不太高,但是也都很巧妙。尤其是主席树的(50)分,由于本人初学主席树,所以没有见过主席树上二分的套路,就被小小的卡了一下。。

    (n <= 200) (and) (m <= 200):前缀和+二分

    (n <= 1) (and) (m <= 500000):主席树+二分,即对主席树每个节点维护一个权值和和本数和。关于最后的一个小细节,下面图片有讲解:

    #include <bits/stdc++.h>
    using namespace std;
    
    int n, m, t;
    
    void subtask_2 () {
    	const int N = 210, M = 1010;
    	static int rec[N][N], sum[N][N][M], num[N][N][M];
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			cin >> rec[i][j];
    			for (int k = rec[i][j]; k >= 1; --k) {
    				sum[i][j][k] = rec[i][j];  //[1, 1] -> [i, j] 间页数 >= k 的书页数和				
    				num[i][j][k] = 1; 		   //[1, 1] -> [i, j] 间页数 >= k 的书本数和 
    			}
    		}
    	}
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			for (int k = 1; k <= 1000; ++k) {
    				sum[i][j][k] += sum[i - 1][j][k] + sum[i][j - 1][k] - sum[i - 1][j - 1][k];
    				num[i][j][k] += num[i - 1][j][k] + num[i][j - 1][k] - num[i - 1][j - 1][k];
    			}
    		}
    	}
    	
    	for (int i = 1; i <= t; ++i) {
    		static int a1, b1, a2, b2, h;
    		cin >> a1 >> b1 >> a2 >> b2 >> h;
    		int l = 1, r = 1000;
    		while (l < r) {
    			int mid = (l + r + 1) >> 1;
    			if (sum[a2][b2][mid] - sum[a2][b1 - 1][mid] - sum[a1 - 1][b2][mid] + sum[a1 - 1][b1 - 1][mid] >= h) {
    				l = mid;
    			} else {
    				r = mid - 1;
    			}
    		}
    		int _num = num[a2][b2][l] - num[a2][b1 - 1][l] - num[a1 - 1][b2][l] + num[a1 - 1][b1 - 1][l];
    		int _sum = sum[a2][b2][l] - sum[a2][b1 - 1][l] - sum[a1 - 1][b2][l] + sum[a1 - 1][b1 - 1][l];
    		while (_sum - l >= h) _sum -= l, _num -= 1;
    		if (_sum < h) {
    			puts ("Poor QLW");
    		} else {
    			cout << _num << endl;
    		}	
    	}
    }
    const int N = 500010;
    
    static int tot = 0, rt[N], arr[N];
    
    struct Segment_Tree {
    	
    	struct Segment_Node {
    		int ls, rs, sz, sum;
    	}t[N << 5];
    	
    	int modify (int root, int l, int r, int _val) {
    		int p = ++tot, mid = (l + r) >> 1;
    		t[p].ls = t[root].ls;
    		t[p].rs = t[root].rs;
    		t[p].sz = t[root].sz + 1;
    		t[p].sum = t[root].sum + _val;
    		if (l != r) { 
    			if (_val <= mid) {
    				t[p].ls = modify (t[root].ls, l, mid, _val);
    			} else {
    				t[p].rs = modify (t[root].rs, mid + 1, r, _val);
    			}
    		}
    		return p;
    	}
    	
    	int build (int l, int r) {
    		int p = ++tot, mid = (l + r) >> 1;
    		t[p].sz = t[p].sum = 0;
    		if (l != r) {
    			t[p].ls = build (l, mid);
    			t[p].rs = build (mid + 1, r);
    		} else {
    			t[p].ls = t[p].rs = 0;
    		}
    		return p;
    	}
    	
    	int query (int u, int v, int l, int r, int k) {
    	    int ans = 0;
    	    while (l < r) {
    	        int mid = (l + r) >> 1;
    	        int lch = t[t[v].rs].sum - t[t[u].rs].sum;
    	        if (lch < k) {
    				ans += t[t[v].rs].sz - t[t[u].rs].sz, k -= lch; 
    				r = mid;
    				v = t[v].ls, u = t[u].ls;
    	        } else {
    				l = mid + 1;
    				v = t[v].rs, u = t[u].rs;
    	    	}
    		}
    	    ans += ceil ((1.0 * k) / (1.0 * l));
    	 	return ans;
    	}
    	
    //	int query (int u, int v, int l, int r, int sumw) {
    //		int mid = (l + r) >> 1;
    //		int del = t[t[v].ls].sum - t[t[u].ls].sum, ans = 0;
    //		if (l != r) {
    //			if (sumw <= del) {
    //				ans += query (t[u].ls, t[v].ls, l, mid, sumw);
    //			} else {
    //				ans += del;
    //				ans += query (t[u].rs, t[v].rs, mid + 1, r, sumw - del);
    //			}
    //		}
    //		return ans;
    //	}
    }tree;
    void subtask_1 () {
    
    	rt[0] = tree.build (1, 1000);
    	for (int i = 1; i <= m; ++i) {
    		cin >> arr[i];
    		rt[i] = tree.modify (rt[i - 1], 1, 1000, arr[i]);
    	}
    	for (int i = 1; i <= t; ++i) {
    		static int a1, b1, a2, b2, h;
    		cin >> a1 >> b1 >> a2 >> b2 >> h;
    		if (tree.t[rt[b2]].sum - tree.t[rt[b1 - 1]].sum < h) {
    			puts ("Poor QLW");
    		} else {
    			cout << tree.query (rt[b1 - 1], rt[b2], 1, 1000, h) << endl;
    		}
    	}
    }
    
    int main () {
    	freopen ("2468.in", "r", stdin);
    	cin >> n >> m >> t;
    	if (n == 1) subtask_1 ();
    	if (n != 1) subtask_2 ();
    }
    
  • 相关阅读:
    【读书笔记】 —— 《数学女孩》
    【读书笔记】 —— 《数学女孩》
    《论语》《大学》《中庸》和孟子
    《论语》《大学》《中庸》和孟子
    零点定理、介值定理
    java学习笔记(3)——面向对象
    linux下的文件操作——批量重命名
    Java学习笔记(4)——JavaSE
    java学习笔记(5)——内部类
    学生管理系统调试——实时错误(实时错误“424”“5”“91”)
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10519649.html
Copyright © 2020-2023  润新知