zoukankan      html  css  js  c++  java
  • 静态区间第K小(整体二分、主席树)

    题目链接

    题解

    主席树入门题

    但是这里给出整体二分解法

    整体二分顾名思义是把所有操作放在一起二分

    想想,如果求([1-n])的第(k)小怎么二分求得?

    我们可以二分答案(k)(O(n))统计有多少个数小于等于(k)

    如果对于每个询问都这么搞,肯定不行

    我们可以发现,如果每次都搞一次,有许多算重复的地方

    (div(l, r, st, ed))表示(k)二分的区间([l-r]), 对应操作答案区间在([st-ed])
    (如果没看懂,先往下看。)

    (mid = (l+r)/2)
    对于每次的(mid), 我们把对(k)往左移还有贡献的 放在一起, 右移的放在一起,这样答案就在一个区间内

    那么如何统计一段区间有多少个数比(k)大呢?
    我们开一个树状数组,如果(x)位上的数大于(k),那么给(x)加上1
    然后统计就是区间求和了

    Code

    #include<bits/stdc++.h>
    
    #define LL long long
    #define RG register
    
    using namespace std;
    const int N = 200010, INF = 1e9;
    struct rec {
    	int op, x, y, z;
    }q[N<<1], lq[N<<1], rq[N<<1];
    int n, m, tot, c[N], ans[N];
    #define lowbit(x) (x&(-x))
    void add(int x, int v) {
    	while (x <= n) c[x] += v, x += lowbit(x);
    	return ;
    }
    int sum(int x) {
    	int res = 0;
    	while (x > 0) res += c[x], x -= lowbit(x);
    	return res;
    }
    int X[N], cnt;
    inline int gi() {
    	RG int x = 0; RG char c = getchar(); bool f = 0;
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') c = getchar(), f = 1;
    	while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
    	return f ? -x : x;
    }
    
    void div(int l, int r, int st, int ed) {
    	if (st > ed) return ;//[l~r]中没有答案
    	if (l == r) {
    		for (int i = st; i <= ed; i++)
    			if (q[i].op) ans[q[i].op] = l;//记录答案
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	int lt = 0, rt = 0;
    	for (int i = st; i <= ed; i++) {
    		if (!q[i].op) {
    			if (q[i].y <= mid) add(q[i].x, 1), lq[++lt] = q[i];//k如果往左移,修改操作还有影响
    			else rq[++rt] = q[i];
    		}
    		else {
    			int res = sum(q[i].y) - sum(q[i].x-1);
    			if (res >= q[i].z) lq[++lt] = q[i];//已经满足至少第K大了,K还可以调小
    			else q[i].z -= res, /*把所有q[i].y<=mid的贡献减去,调大k时就不需要统计这些的贡献了*/rq[++rt] = q[i];
    		}
    	}
    	for (int i = st; i <= ed; i++)
    		if (!q[i].op && q[i].y <= mid) add(q[i].x, -1);//清除
    	for (int i = 1; i <= lt; i++) q[st+i-1] = lq[i];
    	for (int i = 1; i <= rt; i++) q[st+lt+i-1] = rq[i];
    	div(l, mid, st, st+lt-1);
    	div(mid+1, r, st+lt, ed);
    	return ;
    }
    
    int main() {
    	//freopen(".in", "r", stdin);
    	//freopen(".out", "w", stdout);
    	n = gi(); m = gi();
    	for (int i = 1; i <= n; i++) {
    		q[++tot].op = 0, q[tot].x = i, X[++cnt] = q[tot].y = gi();
    	}
    	sort(X+1, X+1+cnt); cnt = unique(X+1, X+cnt+1)-X-1;//离散化
    	for (int i = 1; i <= n; i++)
    		q[i].y = lower_bound(X+1, X+cnt+1, q[i].y)-X;
    	for (int i = 1; i <= m; i++) {
    		q[++tot].op = i; q[tot].x = gi();q[tot].y = gi();q[tot].z = gi();
    	}
    	div(1, n, 1, tot);
    	for (int i = 1; i <= m; i++)
    		printf("%d
    ", X[ans[i]]);
    	return 0;
    }
    
    
  • 相关阅读:
    poj 1743 Musical Theme 后缀数组
    poj 1743 Musical Theme 后缀数组
    cf 432D Prefixes and Suffixes kmp
    cf 432D Prefixes and Suffixes kmp
    hdu Data Structure? 线段树
    关于position和anchorPoint之间的关系
    ios POST 信息
    CALayers的代码示例
    CALayers详解
    ios中得sqlite使用基础
  • 原文地址:https://www.cnblogs.com/zzy2005/p/10147324.html
Copyright © 2011-2022 走看看