• BZOJ2006 超级钢琴


    Description

    ​ 给定一个长度为n的区间,询问前k大的区间和,区间长度(in [L, R])。 $ n, k <= 500000$

    Solution

    ​ 首先求前缀和。把一个区间拆成两个前缀和之差。

    ​ 对于一个固定的右端点。我们首先需要最小化左端点。那么我们就在题目条件允许的范围内先求出左端点最小的位置, 但是一个区间的次大值可能超过别的区间的最大值, 这很麻烦。

    ​ 开一个堆, 维护一个三元组(Pos, Kth, Val), 表示以Pos为右端点,本次查到区间第Kth大,值为Val。

    ​ 然后把一个区间从堆中取出来时, 就把他的(Pos, Kth + 1, Val_)加入堆。

    ​ 然后只要取k次即可。

    ​ 时间复杂度(O((n + k)log_{2}^{n}))

    反思

    ​ 刚刚开始想到把每个右端点的左端点按照大小都加进小根堆, 小根堆大小为K,如果超过就弹出一个。 如果当前值小于堆顶就break, 然后就被卡T到8s

    ​ 最后发现,其实你并不需要把全部的都加入堆,因为只要当前的区间被弹出,才有可能用他的次大值。

    ​ 所以我们只要贪心取最大值就可以的。

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
    #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
    #define clar(a, b) memset((a), (b), sizeof(a))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define Debug(s) debug("The massage in line %d, Function %s: %s
    ", __LINE__, __FUNCTION__, s)
    typedef long long LL;
    typedef long double LD;
    const int BUF_SIZE = (int)1e6 + 10;
    struct fastIO {
        char buf[BUF_SIZE], buf1[BUF_SIZE];
        int cur, cur1;
        FILE *in, *out;
        fastIO() {
            cur = BUF_SIZE, in = stdin, out = stdout;
    		cur1 = 0;
        }
        inline char getchar() {
            if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0;
            return *(buf + (cur++));
        }
        inline void putchar(char ch) {
            *(buf1 + (cur1++)) = ch;
            if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0;
        }
        inline int flush() {
            if (cur1 > 0) fwrite(buf1, cur1, 1, out);
            return cur1 = 0;
        }
    }IO;
    #define getchar IO.getchar
    #define putchar IO.putchar
    int read() {
    	char ch = getchar();
    	int x = 0, flag = 1;
    	for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1;
    	for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    	return x * flag;
    }
    void write(int x) {
    	if(x < 0) putchar('-'), x = -x;
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + 48);
    }
    void putString(char s[], char EndChar = '
    ') {
    	rep(i, 0, strlen(s) - 1) putchar(*(s + i));
    	if(~EndChar) putchar(EndChar);
    }
    
    #define Maxn 500009
    int n, k, L, R, a[Maxn];
    LL s[Maxn];
    template <typename T, int (*Cmp)(T a, T b)> struct Heap {
    	T a[Maxn];
    	int len; 
    	void push(T val) {
    		a[++len] = val;
    		push_heap(a + 1, a + len + 1, Cmp);
    	}
    	T pop() { pop_heap(a + 1, a + len + 1, Cmp); return a[len--];}
    	T top() {return a[1];}
    	T empty() { return !len;}
    };
    LL W[Maxn], d, Ns[Maxn];
    namespace Chairman {
    	int t[Maxn * 64], lc[Maxn * 64], rc[Maxn * 64], amt, rt[Maxn];
    	int build(int l, int r) {
    		int u = ++amt, mid = (l + r) >> 1;
    		if(l == r) return u;
    		lc[u] = build(l, mid);
    		rc[u] = build(mid + 1, r);
    		return u;
    	}
    	int modify(int rt, int l, int r, int pos) {
    		int mid = (l + r) >> 1, u = ++amt;
    		t[u] = t[rt] + 1; lc[u] = lc[rt], rc[u] = rc[rt];
    		if(l == r) return u;
    		(pos <= mid) ? (lc[u] = modify(lc[rt], l, mid, pos)) : (rc[u] = modify(rc[rt], mid + 1, r, pos));
    		return u;
    	}
    	int query(int rt0, int rt1, int l, int r, int pos) {
    		if(l == r) return l;
    /**/	int res = t[lc[rt1]] - t[lc[rt0]], mid = (l + r) >> 1;
    		return (res >= pos) ? (query(lc[rt0], lc[rt1], l, mid, pos)) : (query(rc[rt0], rc[rt1], mid + 1, r, pos - res));
    	}
    }
    namespace INIT {
    	void Main() {
    		n = read(), k = read(); L = read(), R = read();
    		rep(i, 1, n) a[i] = read(), W[i + 1] = (s[i] = s[i - 1] + a[i]);
    		sort(W + 1, W + n + 2);
    		d = unique(W + 1, W + n + 2) - W - 1;
    		rep(i, 0, n) Ns[i] = lower_bound(W + 1, W + d + 1, s[i]) - W;
    	}
    }
    namespace SOLVE {
    	using namespace Chairman;
    	struct node {
    		int pos, kth;
    		LL val;
    	};
    	int cmp(node tarA, node tarB) { return tarA.val < tarB.val;}
    	Heap <node, cmp> hep;
    	void Main() {
    		rt[0] = build(1, d), rt[1] = modify(rt[0], 1, d, Ns[0]);
    		rep(i, 1, n) rt[i + 1] = modify(rt[i], 1, d, Ns[i]);
    		rep(i, 1, n) {
    			int bound1 = max(i - R, 0), bound2 = i - L;
    			if(bound2 < bound1) continue;
    			int cur = query(rt[bound1], rt[bound2 + 1], 1, d, 1);
    			hep.push((node){i, 1, s[i] - W[cur]});
    		}
    		LL ans = 0;
    		rep(i, 1, k) {
    			node Tmp = hep.pop();
    			ans += Tmp.val;
    			int bound1 = max(Tmp.pos - R, 0), bound2 = Tmp.pos - L;
    			if(Tmp.kth + 1 > bound2 - bound1 + 1) continue;
    			int cur = query(rt[bound1], rt[bound2 + 1], 1, d, Tmp.kth + 1);
    			hep.push((node){Tmp.pos, Tmp.kth + 1, s[Tmp.pos] - W[cur]});
    		}
    		cout << ans << endl;
    	}
    }
    int main() {
    #ifdef Qrsikno
    	freopen("BZOJ2006.in", "r", stdin);
    	freopen("BZOJ2006.out", "w", stdout);
    #endif
    	INIT :: Main();
    	SOLVE :: Main();
    #ifdef Qrsikno
    	debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
    	return IO.flush();
    }
    
    

  • 相关阅读:
    mac中导出CSV格式在excel中乱码
    Android Gradle与Gradle插件的对应关系
    【算法】二叉树的前序、中序、后序、层序遍历和还原。
    关于Java虚拟机
    从Java synchronized和volatile说起
    【程小白】Java基本特性
    Android一键锁屏APP
    Fragment的生命周期
    学习大数据必须了解的大数据开发课程大纲
    学习大数据这三个关键技术是一定要掌握!
  • 原文地址:https://www.cnblogs.com/qrsikno/p/9732751.html
Copyright © 2020-2023  润新知