1878: [SDOI2009]HH的项链
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 5317 Solved: 2624
[ Submit][ Status][ Discuss]
Description
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
Input
第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。
Output
M行,每行一个整数,依次表示询问对应的答案。
Sample Input
6
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
2
4
据说当时出这道题的时候,还没有主席树这东西
现在有了主席树,就成水题了
记L[i]为第i个数字上一次出现的位置,那么对于每次询问[x, y],答案就是这个区间内满足L[i]<x的数的个数
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct
{
int l, r;
int val;
}Tree;
Tree s[4000005];
int n, cnt, pos[1000005], L[100005], a[100005], t[100005];
int Build(int l, int r)
{
int m, root;
m = (l+r)/2;
root = ++cnt;
if(l==r)
{
s[root].val = 0;
return root;
}
s[root].l = Build(l, m);
s[root].r = Build(m+1, r);
s[root].val = s[s[root].l].val+s[s[root].r].val;
return root;
}
int Update(int root, int k)
{
int now, temp, m, l, r;
now = temp = ++cnt;
l = 1, r = n+1;
while(l<r)
{
m = (l+r)/2;
s[now].val = s[root].val+1;
if(k<=m)
{
s[now].l = ++cnt;
s[now].r = s[root].r;
root = s[root].l;
r = m;
now = cnt;
}
else
{
s[now].r = ++cnt;
s[now].l = s[root].l;
root = s[root].r;
l = m+1;
now = cnt;
}
}
s[now].val = s[root].val+1;
return temp;
}
int Query(int root, int l, int r, int a, int b)
{
int ans, m;
ans = 0;
if(l>=a && r<=b)
return s[root].val;
m = (l+r)/2;
if(a<=m)
ans += Query(s[root].l, l, m, a, b);
if(b>=m+1)
ans += Query(s[root].r, m+1, r, a, b);
return ans;
}
int main(void)
{
int i, m, l, r;
scanf("%d", &n);
for(i=2;i<=n+1;i++)
{
scanf("%d", &a[i]);
L[i] = max(pos[a[i]], 1);
pos[a[i]] = i;
}
t[1] = Build(1, n+1);
for(i=2;i<=n+1;i++)
t[i] = Update(t[i-1], L[i]);
scanf("%d", &m);
while(m--)
{
scanf("%d%d", &l, &r);
l += 1, r += 1;
printf("%d\n", Query(t[r], 1, n+1, 1, l-1)-Query(t[l-1], 1, n+1, 1, l-1));
}
return 0;
}