• 「Codeforces 429D」Destiny


    Description

    给定一个长度为 (n) 的数列 ({a_1,a_2,cdots ,a_n})(q) 次询问。

    每个询问给定一段区间 ([l,r]) 以及一个整数 (k),求该区间中出现次数大于 (frac{r - l + 1}{k}) 次的最小数。如果不存在输出 -1。

    Hint

    (1le n,qle 3 imes 10^5)

    (1le a_ile n, 1le lle rle ,2le kle 5)

    Solution

    先对数列 (a) 建出可持久化线段树(主席树)。

    然后重点是查询。

    对于某个询问,设 (c = frac{r - l + 1}{k}) ,那么在主席树的某一个结点:

    计算出左右儿子的 size,即值在左右儿子管辖值域的数的个数,分别记为 (sL,sR)

    由于要求这个数字尽量小,因此先在左子树中查找,再右子树。

    但即便如此,那也不是两颗子树都是要搜的。

    显然如果 (sL le c) ,那么左边就不可能有答案,没有搜的必要。右边同理。

    其他部分就是平平常常的主席树。时空复杂度 (O(nlog n))

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : Codeforces 429D Destiny
     */
    #include <iostream>
    using namespace std;
    
    const int N = 3e5 + 5;
    const int S = N << 5;
    
    int lc[S], rc[S];
    int size[S];
    int total = 0;
    int root[N];
    #define mid ((l + r) >> 1)
    
    int build(int l, int r) {
    	int rt = ++total;
    	if (l == r) return rt;
    	lc[rt] = build(l, mid);
    	rc[rt] = build(mid + 1, r);
    	return rt;
    }
    
    int update(int pre, int l, int r, int p) {
    	int rt = ++total;
    	size[rt] = size[pre] + 1;
    	lc[rt] = lc[pre], rc[rt] = rc[pre];
    	if (l == r) return rt;
    	if (p <= mid) lc[rt] = update(lc[pre], l, mid, p);
    	else rc[rt] = update(rc[pre], mid + 1, r, p);
    	return rt;
    }
    
    int query(int s, int t, int l, int r, int c) {
    	if (l == r) return l;
    	int sL = size[lc[t]] - size[lc[s]];
    	int sR = size[rc[t]] - size[rc[s]];
    	int temp = -1;
    	if (sL > c)
    		if ((temp = query(lc[s], lc[t], l, mid, c)) != -1)
    			return temp;
    	if (sR > c)
    		if ((temp = query(rc[s], rc[t], mid + 1, r, c)) != -1)
    			return temp;
    	return -1;
    }
    
    int n, q;
    signed main() {
    	ios::sync_with_stdio(0);
    	cin >> n >> q;
    	root[0] = build(1, n);
    	
    	for (register int a, i = 1; i <= n; i++)
    		cin >> a, root[i] = update(root[i - 1], 1, n, a);
    	
    	while (q--) {
    		int l, r, k;
    		cin >> l >> r >> k;
    		k = (r - l + 1) / k;
    		cout << query(root[l - 1], root[r], 1, n, k) << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    报表选型应该知道的
    报表工具——开源还是商用
    地图报表怎么做?
    关于报表在移动端展现需你需要知道哪些?
    报表怎样实现滚动的公告效果?
    加速JDBC的快捷方法
    百万级分组大报表开发与呈现
    秒级展现的百万级大清单报表怎么做
    润乾集算器技术文档汇总
    报表使用相关知识及技巧汇总
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12676240.html
Copyright © 2020-2023  润新知