NC20545 [HEOI2012]采花
题目链接
关键点:
1、题目要求求出能采到花的颜色数。
2、记下每种颜色的前一个位置,和前前个位置。当一朵花第一次出现时,我们将其当作该种花前前个位置。当一朵花出现第二次时,将该位置当作该种花前一个位置。并且说明所有包含前前个花的区间都可以采该颜色的花,所以颜色数+1。当一朵花出现三次以上时,我们将包含前一朵花的区间+1,因为如果左区间从前一朵花开始,到当前这朵花结束,刚刚好为两朵花,那么颜色数可以+1。而对于包含前前朵花的区间则要-1,不然颜色就会重复计算
3、我们将所求的区间按照右区间排序,从小到大开始求,最后记得要按照题目给的顺序输出答案
# include <bits/stdc++.h>
using namespace std;
const int N = 10000000+10;
int res[N];
int ans[N];
int a[N];
int n, c, m;
int mp1[N], mp2[N];
struct ty{
int l, r, id;
}t[10000000+10];
bool cmp(ty t1, ty t2)
{
return t1.r < t2.r;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int p, int x)
{
while (p<=n)
{
res[p] += x;
p += lowbit(p);
}
}
int calc(int p)
{
int sum = 0;
while (p>0)
{
sum += res[p];
p -= lowbit(p);
}
return sum;
}
int main()
{
scanf("%d%d%d", &n, &c, &m);
for (int i=1; i<=n; i++)
{
scanf("%d", &a[i]);
}
while (lowbit(n) != n) n+=lowbit(n);
for (int i=1; i<=m; i++)
{
t[i].id = i;
scanf("%d%d", &t[i].l, &t[i].r);
}
sort(t+1, t+1+m, cmp);
int j = 1;
for (int i=1; i<=m; i++)
{
for (; j<=t[i].r; j++)
{
if (!mp1[a[j]]) mp1[a[j]] = j;
else{
if (!mp2[a[j]])
{
add(mp1[a[j]], 1);
mp2[a[j]] = j;
}
else
{
add(mp2[a[j]], 1);
add(mp1[a[j]], -1);
mp1[a[j]] = mp2[a[j]];
mp2[a[j]] = j;
}
}
}
ans[t[i].id] = calc(t[i].r) - calc(t[i].l-1);
}
for (int i=1; i<=m; i++)
printf("%d\n", ans[i]);
return 0;
}