主席树求解区间不同数的个数:P1972

经典模型:求区间不同数的个数

方法:主席树

其实思路与 树状数组 解决这题的思路是一模一样的。只不过主席树支持强制在线

原理:对于一个右端点,不管我们的左端点询问在哪。对于同一个数多次出现的情况,我们实际上只关注离右端点最近的点。
在实现时,我们在新增的i处加入1个贡献。然后再删去上一个a[i]出现的位置的1个贡献.然后查询就是对一个历史版本数的一个简单的区间和查询

所以实际上这里其实不像 可持久化值域线段树 了.而是可持久化数组。我们用主席树维护的是 当右端点是 i i i 时,每个位置对答案的贡献

我们就是利用主席树将每一个右端点的数组的状态都记录下来了。所以查询的时候直接查询历史版本即可。这也就是为什么主席树做这道题能够强制在线。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define mid ((l + r) >> 1)
const int maxn = 2e6 + 5;
template <typename T>
void read(T & x)
{
    
    
    x = 0;T f = 1;
    char ch = getchar();
    while(!isdigit(ch)){
    
    
	if(ch == '-') f = -1;
	ch = getchar();
    }
    while (isdigit(ch)){
    
    
	x = x * 10 + (ch ^ 48);
	ch = getchar();
    }
    x *= f;
}
template <typename T>
void write(T x)
{
    
    
    if(x < 0){
    
    
       putchar('-');
       x = -x;
      }
    if (x > 9)    write(x / 10);
    putchar(x % 10 + '0');
    return;
}
int a[maxn];
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 (int l , int r , int t , int L)
{
    
    
    if (l == r) return sum[t];
    int ans = 0;
    if (L <= mid) ans = ask(l , mid , ls[t] , L) + sum[rs[t]];
    else ans += ask(mid + 1 , r , rs[t] , L);
    return ans;
}
int last[maxn];
int main()
{
    
    
    int n; read(n);
    int up = 1e6;
    for (int i = 1 ; i <= n ; i++){
    
    
        read(a[i]);
        if (last[a[i]]) {
    
    
           rt[i] = add(1 , up , rt[i - 1] , last[a[i]] , -1);
           rt[i] = add(1 , up , rt[i] , i , 1);
        }
        else{
    
    
            rt[i] = add(1 , up , rt[i - 1] , i , 1);
        }
        last[a[i]] = i;
    }
    int m; read(m);
    while (m--){
    
    
        int l , r;read(l);read(r);
        write(ask(1 , up , rt[r] , l));puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/109018868
今日推荐