主席树/树状数组(离线)查区间不同元素个数模板

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;
}
发布了69 篇原创文章 · 获赞 0 · 访问量 2852

猜你喜欢

转载自blog.csdn.net/Stagflation/article/details/104026836