主席樹/樹狀數組(離線)查區間不同元素個數模板

2020.1.17 星期五
學完線段樹kb寫法膨脹了,開始學習主席樹和莫隊了,莫隊和離線數組的套路基本喫透了,莫隊是像貪心那樣子對查詢的區間端點排個序用前綴和減掉相應的區間之前的不同的數字和來達到降低複雜度的目的,避免了一定量的重複查找,之前大佬把區間端點的排序稱作奇偶性排序,搞得我暈了半天,樹狀數組更簡單了,就是建立在前綴和上的數據結構,這兩個模板mark。洛谷oj模板題,hh的項鍊。
主席樹寫法

#include <bits/stdc++.h>
using namespace std;
#define limit 2000000 + 5//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3ff
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define Modulo 1000000
#define ff(a) printf("%d\n",a );
#define MOD 1000000000 + 7
#define midd l + (r - l ) / 2
#define mint(a,b,c) min(min(a,b), c)
#define FOPEN freopen("C:\\Users\\administrator01\\CLionProjects\\untitled19\\data.txt", "rt", stdin)
typedef long long ll;
void read(int &x){
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}//快讀
int read(){
    int x;
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    return x;
}//快讀
int n , m;
int cnt, tree[limit<< 2], num[limit];
int a[limit << 2], lson[limit<<2] , rson[limit << 2], status[limit];
int build(int l, int r){
    int root = cnt++;
    a[root] = 0;
    if(l != r){
        lson[root] = build(l , midd);
        rson[root] = build(midd + 1 , r);
    }
    return root;
}
int update(int root ,int pos, int val){
    int rt = cnt++, tmp = rt;
    a[rt] = a[root] + val;
    int l = 1 , r = n;
    while(l < r){
        if(pos <= midd){
            lson[rt] = cnt++;
            rson[rt] = rson[root];
            rt = lson[rt];
            root = lson[root];
            r = midd;
        }else{
            rson[rt] = cnt++;
            lson[rt] = lson[root];
            rt = rson[rt];
            root = rson[root];
            l = midd + 1;
        }
        a[rt] = a[root] + val;
    }
    return tmp;
}
ll query(int root, int pos){
    ll ret = 0;
    int l = 1, r = n;
    while(pos < r){
        if(pos <= midd){
            r = midd;
            root = lson[root];
        }else{
            ret += a[lson[root]];
            l = midd + 1;
            root = rson[root];
        }

    }
    return ret + a[root];
}
int main(){
#ifdef LOCAL
    FOPEN;
#endif
    cnt = 0;
    n = read();
    tree[n + 1] = build(1, n);
    for(int i = 1 ; i <= n ; ++i){
        num[i] = read();
    }
    for(int i = n ; i >= 1 ; -- i){
        if(status[num[i]]){
            int pos = update(tree[i + 1] , status[num[i]], -1);
            tree[i] = update(pos, i , 1);
        }else{
            tree[i] = update(tree[i + 1] , i , 1);
        }
        status[num[i]] = i;
    }
    for(int i = read() ; i >= 1; --i ){
        int l = read(), r = read();
        ll ans = query(tree[l], r);
        printf("%lld\n" , ans);
    }
    return 0;
}

樹狀數組寫法

#include <bits/stdc++.h>
using namespace std;
#define limit 1000000 + 5//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3ff
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define Modulo 1000000
#define ff(a) printf("%d\n",a );
#define MOD 1e9 + 7
#define exam(i) printf("%d here we go\n", i)
#define FOPEN freopen("C:\\Users\\administrator01\\CLionProjects\\untitled19\\data.txt", "rt", stdin)
typedef long long ll;
void read(int &x){
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}//快讀
int read(){
    int x;
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    return x;
}//快讀
struct ask{
    int l, r, id;
    ask(int ll = 0, int rr = 0, int idd = 0):l(ll) , r(rr), id(idd){}
    bool operator<(const ask &rhs)const{
        return r < rhs.r;
    }
}query[limit];
int tree[limit << 2] , a[limit << 2] , status[limit];
ll ans[limit];
int n;
void add(int idx, int val){
    for(int i = idx ; i <= n ; i += lowbit(i)){
        tree[i] += val;
    }
}
ll sum(int idx){
    ll res = 0;
    for(int i = idx ; i > 0 ; i -= lowbit(i)){
        res += tree[i];
    }
    return res;
}
int main(){
    //FOPEN;
    n = read();
    //memset(status , 0 , sizeof(status));
    for(int i = 1 ; i <= n ; ++i){
        a[i] = read();
    }
    int q = read();
    for(int i = 1 ; i <= q; ++i){
        query[i].l = read();
        query[i].r = read();
        query[i].id = i;
    }
    sort(query + 1 , query + q + 1);
    int iter = 1;
    for(int i = 1 ; i <= q ; ++i){
        for(int j = iter ; j <= query[i].r ; ++j) {
            if (status[a[j]]) {
                add(status[a[j]], -1);
            }
            add(j , 1);
            status[a[j]] = j;

        }
            iter = query[i].r + 1;
            ans[query[i].id] = sum(query[i].r) - sum(query[i].l - 1);//減去樹狀數組

    }
    for(int i = 1 ; i <= q ; ++i){
        printf("%d\n", ans[i]);

    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章