HDU3333 Turing Tree (可持久化线段树)

题意:

给定一个长度为n的序列,给定m个查询,每次查询区间[L,R]范围内不同元素的和。 解决这个问题你可以使用树状数组或者莫队或者主席树

题解:

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e4+100;
const int M=maxn*40;
int n,m,q,tot;
int a[maxn];
int T[maxn];
int lson[M];
int rson[M];
long long c[M];
int build (int l,int r) {
    int root=tot++;
    c[root]=0;
    if (l!=r) {
        int mid=(l+r)>>1;
        lson[root]=build(l,mid);
        rson[root]=build(mid+1,r);
    }
    return root;
}
int up (int root,int pos,int val) {
    int newRoot=tot++;
    int tmp=newRoot;
    c[newRoot]=c[root]+val;
    int l=1,r=n;
    while (l<r) {
        int mid=(l+r)>>1;
        if (pos<=mid) {
            lson[newRoot]=tot++;
            rson[newRoot]=rson[root];
            newRoot=lson[newRoot];
            root=lson[root];
            r=mid;
        }
        else {
            rson[newRoot]=tot++;
            lson[newRoot]=lson[root];
            newRoot=rson[newRoot];
            root=rson[root];
            l=mid+1;
        }
        c[newRoot]=c[root]+val; 
    }
    return tmp;
}

long long query (int root,int l,int r,int L,int R) {
    if (l>=L&&r<=R) return c[root];
    int mid=(l+r)>>1;
    long long ans=0;
    if (L<=mid) ans+=query(lson[root],l,mid,L,R);
    if (R>mid) ans+=query(rson[root],mid+1,r,L,R);
    return ans;
}

int main () {
    int _;
    scanf("%d",&_);
    while (_--) {
        scanf("%d",&n);
        tot=0;
        for (int i=1;i<=n;i++) scanf("%d",a+i);
        map<int,int> mp;
        T[n+1]=build(1,n);
        for (int i=n;i;i--) {
            if (mp.find(a[i])==mp.end()) {
                T[i]=up(T[i+1],i,a[i]);
            }
            else {
                int tt=up(T[i+1],mp[a[i]],-a[i]);
                T[i]=up(tt,i,a[i]);
            }
            mp[a[i]]=i;
        } 
        scanf("%d",&q);
        while (q--) {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(T[l],1,n,1,r));
        }
    }
}

 

posted @ 2020-11-16 19:37  zlc0405  阅读(148)  评论(0编辑  收藏  举报