主席树-HDU5919(CCPC2016长春)

题目大意:

给一个长度为n的序列.给Q次询问,每次询问 [ L , R ] [L,R] [L,R].假设里面有 k k k个不同的数.求从左到右第 ⌈ k 2 ⌉ \lceil\frac{k}{2}\rceil 2k个不同的数出现的位置.( n , q ≤ 2 e 5 n,q \leq 2e5 n,q2e5).强制在线.

题目思路:

前置知识点:主席树求区间不同的数的个数:(个人认为知道这个点,这道题就做完80%了)
https://blog.csdn.net/qq_35577488/article/details/109018868

这里需要求的是从左到右的位置.顺序建树行不通(因为我们只保存一个数最后出现的位置,与题目意思不相符合).

那么自然想到逆序建树,查询 [ L , R ] [L,R] [L,R]时,先查询区间不同数个数.再直接对第 L L L颗树查询 第 ⌈ k 2 ⌉ \lceil\frac{k}{2}\rceil 2k个 贡献1 出现的位置即可.(都是基操…)

一道银牌题,还不错.难度适中

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define mid ((l + r) >> 1)
const int maxn = 4e5 + 5;
int sum[maxn << 5] , ls[maxn << 5] , rs[maxn << 5] , rt[maxn] , tot;
int add (int l , int r , int t , int p , int c)
{
    
    
    int now = ++tot;
    ls[now] = ls[t];
    rs[now] = rs[t];
    sum[now] = sum[t] + c;
    if (l == r) return now;
    if (p <= mid) ls[now] = add (l , mid , ls[now] , p , c);
    else rs[now] = add (mid + 1 , r , rs[now] , p , c);
    return now;
}
int ask_num (int t , int l , int r , int L , int R)
{
    
    
    if (L > R) return 0;
    if (L <= l && r <= R) return sum[t];
    int ans = 0;
    if (L <= mid) ans += ask_num(ls[t] , l , mid , L , R);
    if (R > mid) ans += ask_num(rs[t] , mid + 1 , r , L , R);
    return ans;
}
int ask_pos (int t , int l , int r , int k)
{
    
    
    if (l == r) return l;
    if (sum[ls[t]] >= k) return ask_pos(ls[t] , l , mid , k);
    return ask_pos(rs[t] , mid + 1 , r , k - sum[ls[t]]);
}
int last[maxn] , a[maxn] , n , m;
int main()
{
    
    
    int t; scanf("%d" , &t);
    int ca = 0;
    while (t--){
    
    
        tot = 0;
        scanf("%d%d" , &n , &m);
        memset (last , 0 , sizeof last);
        for (int i = 0 ; i <= n ; i++){
    
    
            rt[i] = 0;
        }
        int up = n << 5;
        for (int i = 0; i <= up ; i++){
    
    
            sum[i] = ls[i] = rs[i] = 0;
        }
        rt[n + 1] = 0;
        for (int i = 1; i <= n ; i++){
    
    
            scanf("%d" , a + i);
        }
        for (int i = n; i >= 1 ; i--){
    
    
            if (last[a[i]]){
    
    
                rt[i] = add (1 , n , rt[i + 1] , last[a[i]] , -1);
                rt[i] = add (1 , n , rt[i] , i , 1);
            }else {
    
    
                rt[i] = add (1 , n , rt[i + 1] , i , 1);
            }
            last[a[i]] = i;
        }
        int lastans = 0;
        printf("Case #%d: " , ++ca);
        while (m--){
    
    
            int l , r , x ,y;scanf("%d%d" , &x , &y);
            l = min((x + lastans) % n + 1 ,(y + lastans) % n + 1);
            r = max((x + lastans) % n + 1 ,(y + lastans) % n + 1);
            int k = ask_num(rt[l] , 1 , n , l , r);
            k = (k - 1) / 2 + 1;
            lastans = ask_pos(rt[l] , 1 , n , k);
            if (m == 0)
                printf("%d\n" , lastans);
            else
                printf("%d " , lastans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/109027936