其他分享
首页 > 其他分享> > Codeforces-840D - Destiny(主席树上二分,思维)

Codeforces-840D - Destiny(主席树上二分,思维)

作者:互联网

题目大意:

给你一个序列,一些查询

每次查询区间[L,R]中出现次数大于T的最小的a[i]是多少

题目思路:

一眼主席树

但是这个题目在于如何用好这个条件

2 ≤ k ≤ 5

假设这个序列长度是1000,k=5

那么就是找出现次数大于200的,但是这样的数字最多有多少个呢?  很明显 

不会超过k个

然后我查询一个区间的数字个数的和的时候,如果小于T,直接退出

然后继续搜下去(这里不会有k<=5的限制,会退出的很快)

这里因为要求最小值

所以每次先搜左边再搜右边

搜到答案直接退出就ok了

CODE:

ll n, val[maxn], qq, indexx, ans,rt[maxn];
struct node
{
    ll ls, rs, num;
} a[maxn * 32];
void insert(ll pre, ll &now, ll l, ll r, ll pos)
{
    now = ++indexx;
    a[now] = a[pre], a[now].num++;
    if(l == r) return ;
    ll mid = (l + r) >> 1;
    if(pos <= mid) insert(a[pre].ls, a[now].ls, l, mid, pos);
    else insert(a[pre].rs, a[now].rs, mid + 1, r, pos);
}
void  query(ll v, ll u, ll l, ll r, ll k)
{
    if(ans != -1) return ;
    ll num = a[u].num - a[v].num;
    if(num < k) return ;
    if(l == r)
    {
        if(num >= k) ans = l;
        return ;
    }
    ll mid = (l + r) >> 1ll;
    query(a[v].ls, a[u].ls, l, mid, k);
    query(a[v].rs, a[u].rs, mid + 1, r, k);

}
int main()
{
    n = read(), qq = read();
    rep(i, 1, n) val[i] = read(), insert(rt[i - 1], rt[i], 1, 300000, val[i]);
    while(qq--)
    {
        ll L, R, T;
        L = read(), R = read(), T = read();
        ll temp = (R - L + 1) / T;
        ans = -1;
        query(rt[L - 1], rt[R], 1, 300000, temp + 1);
        out(ans);
        puts("");
    }
    return  0 ;
}
View Code

 

标签:rt,Destiny,read,ll,840D,Codeforces,mid,ans,now
来源: https://www.cnblogs.com/UpMing/p/14668875.html