zoukankan      html  css  js  c++  java
  • 「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;
    }
    
  • 相关阅读:
    js 置顶操作
    js input输入数量控制
    js 时间倒计时
    html内容垂直居中
    大图片随浏览器水平居中显示
    img,display:inline相关间隙样式问题
    js淡入淡出轮换思想(1)
    js 禁止|阻止滚动条滚动
    kotlin学习--第一个kotlin项目
    jdk8+Mybatis3.5.0+Mysql读取LongBlob失败
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12676240.html
Copyright © 2011-2022 走看看