题目:https://vjudge.net/problem/SPOJ-DQUERY
思路:维护每个数上一次出现的位置,若之前出现过,每次更新将上一次出现位置的树链复制即可,等价于将出现多次的数看作只出现一次。
#include <bits/stdc++.h>
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];
vector<int>pos;
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<m; ++i) {
scanf("%d%d",&l,&r);
printf("%d\n",query(root[l-1],root[r],1,n,l,r));
}
}
}