Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 600600 points
Problem Statement
We have NN colored balls arranged in a row from left to right; the color of the ii-th ball from the left is cici.
You are given QQ queries. The ii-th query is as follows: how many different colors do the lili-th through riri-th balls from the left have?
Constraints
- 1≤N,Q≤5×1051≤N,Q≤5×105
- 1≤ci≤N1≤ci≤N
- 1≤li≤ri≤N1≤li≤ri≤N
- All values in input are integers.
Input
Input is given from Standard Input in the following format:
NN QQ c1c1 c2c2 ⋯⋯ cNcN l1l1 r1r1 l2l2 r2r2 :: lQlQ rQrQ
Output
Print QQ lines. The ii-th line should contain the response to the ii-th query.
Sample Input 1 Copy
Copy
4 3 1 2 1 3 1 3 2 4 3 3
Sample Output 1 Copy
Copy
2 3 1
- The 11-st, 22-nd, and 33-rd balls from the left have the colors 11, 22, and 11 - two different colors.
- The 22-st, 33-rd, and 44-th balls from the left have the colors 22, 11, and 33 - three different colors.
- The 33-rd ball from the left has the color 11 - just one color.
Sample Input 2 Copy
Copy
10 10 2 5 6 5 2 1 7 9 7 2 5 5 2 4 6 7 2 2 7 8 7 9 1 8 6 9 8 10 6 8
Sample Output 2 Copy
Copy
1 2 2 1 2 2 6 3 3 3
思路:树状数组模拟。
做法:首先将每个区间按右边界从小到大排序,对于每个区间,从左到右遍历颜色,每个颜色只保留一个,如果这个颜色有两个,那么就去掉左边的一个,保留右边的一个,最后计算区间的和,因为每个颜色只保留了一个,所以区间和就是种类数。
为什么要保留右边的:因为遍历是按照右边界从小到大的顺序排列,保留靠右的节点可以保证在即将出现的边界里只有被保留的节点。
例:1 2 3 4 1 2 3
如果有两个区间 1 4 和 2 6 那么在第一个区间里,第一个1有意义,而在第二个区间里第一个1没有意义有,所以第二个1出现时应保留第二个1,并在树状数组里去除第一个1。
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 1e6 + 10;
int tr[N];
int n,m;
int last[N];
int ans[N];
struct node{
int l,r,pos;
}nod[N];
int color[N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int a)
{
for(int i=x; i<=n; i+=lowbit(i)) tr[i]+=a;
}
int query(int x)
{
int rul = 0;
for(int i=x; i; i-=lowbit(i)) rul += tr[i];
return rul;
}
bool cmp(node a, node b)
{
return a.r < b.r;
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++) scanf("%d",&color[i]);
for(int i=1; i<=m; i++)
{
scanf("%d %d",&nod[i].l,&nod[i].r);
nod[i].pos = i;
}
sort(nod+1, nod+m+1, cmp);
int next = 1;
for(int i=1; i<=m; i++)
{
for(int j=next; j<=nod[i].r; j++)
{
if(last[color[j]]) add(last[color[j]], -1);
last[color[j]] = j;
add(j, 1);
}
next = nod[i].r+1;
ans[nod[i].pos] = query(nod[i].r) - query(nod[i].l-1);
}
for(int i=1; i<=m; i++)
{
cout<<ans[i]<<endl;
}
return 0;
}
不明白的可以看下这道题的题解:https://www.luogu.com.cn/problem/P1972