P1972 [SDOI2009] HH的项链(树状数组

#include
using namespace std;
using VI = vector;
using ll = long long;
int tree[2000010];
int n,m;
int lowbit(int x){
    return x & (-x);
}
int quary(int x){
    int res = 0 ;
    for(int i = x ; i ; i -= lowbit(i)){
        res += tree[i];
    }
    return res;
}
void change(int x , int v){
    for(int i = x; i <= n; i += lowbit(i)){
        tree[i] += v;
    }
}
struct range{
    int l , r , id;
    bool operator < (const range & u){
        return r < u.r;
    }
}a[2000010];
int h[2000010];
int vis[2000010];
int ans[2000010];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n;
    for(int i = 1 ; i <= n ; i++){
        cin>>h[i];
    }
    cin>>m;
    for(int i = 1 ; i <= m ; i++){
        cin>>a[i].l>>a[i].r;
        a[i].id = i;
    }
    sort(a + 1 , a + 1 + m);
    int s = 1;
    for(int i = 1 ; i <= m ; i++){
        for(int j = s ; j <= a[i].r ; j++){
            if(vis[h[j]]) change(vis[h[j]] , -1);
            change(j , 1);
            vis[h[j]] = j;
        }
        s = a[i].r + 1;
        ans[a[i].id] = quary(a[i].r) - quary(a[i].l - 1);
    }

    for(int i = 1 ; i <= m ; i++){
        cout<

 用树状数组实现离线查询

如果维护前缀的种类就是这个题的难点,

将查询区间按照右端点为第一关键字  左端点为第二关键字,从小到大排序,

同时开一个数组记录每个种类的石头的位置,

如果一个石头在之前已经出现过,那么就将这个石头的种类尽量放到右边。

这个种类石头的出现的上一位的种类数减去1

你可能感兴趣的:(数据结构题,c++)