区间不同数的个数(可持久化线段树)

 题目:https://vjudge.net/problem/SPOJ-DQUERY

思路:维护每个数上一次出现的位置,若之前出现过,每次更新将上一次出现位置的树链复制即可,等价于将出现多次的数看作只出现一次。

#include 
using namespace std;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
typedef long long LL;
const int N = 30010;

struct seg{int lson, rson, cnt;}T[N*20];
int root[N], tot, arr[N], last_pos[N];
vectorpos;
void init(){
    pos.clear();tot=0;
    CLR(root,0); CLR(last_pos,0);
    T[0].cnt=T[0].lson=T[0].rson=0;
}
void update(int &cur, int ori, int l, int r, int pos, int flag){
    cur = ++tot; T[cur] = T[ori]; T[cur].cnt += flag;
    if(l == r) return ;
    int mid = l+r >> 1;
    if(pos <= mid) update(T[cur].lson, T[ori].lson, l, mid, pos, flag);
    else update(T[cur].rson, T[ori].rson, mid+1, r, pos, flag);
}
int query(int S, int E, int l,int r, int x, int y){
    if(x<=l && y>=r) return T[E].cnt - T[S].cnt;
    else {
        int mid = l+r >> 1;
        if(y <= mid) return query(T[S].lson, T[E].lson, l, mid, x, y);
        else if(x > mid) return query(T[S].rson, T[E].rson, mid+1, r, x, y);
        else return query(T[S].lson,T[E].lson, l, mid, x, mid)+query(T[S].rson, T[E].rson, mid+1, r, mid+1, y);
    }
}
int main()
{
    int n,m,i,l,r;
    while (~scanf("%d",&n)) {
        init();
        for (i=1; i<=n; ++i) scanf("%d",&arr[i]), pos.push_back(arr[i]);
        sort(pos.begin(),pos.end()); pos.erase(unique(pos.begin(),pos.end()),pos.end());
        int temp_rt=0; scanf("%d",&m);
        for (i=1; i<=n; ++i) {
            arr[i]=lower_bound(pos.begin(),pos.end(),arr[i])-pos.begin()+1;
            if(!last_pos[arr[i]]) {
                update(root[i],root[i-1],1,n,i,1);
                last_pos[arr[i]]=i;
            } else {
                update(temp_rt,root[i-1],1,n,last_pos[arr[i]],-1);
                update(root[i],temp_rt,1,n,i,1);
                last_pos[arr[i]]=i;
            }
        }
        for (i=0; i

 

你可能感兴趣的:(数据结构,主席树)