题目链接
个人感觉这是一道很精妙的写法,首先如果在线求的话不好求,那么考虑离线,离线的话,肯定要排序,那就得看按左端点
排序还是按右端点排序,这里按右端点排序,至于为什么等下就知道了。我们要找的是区间内不同数的个数,因为按照
右端点排序了,所以根据贪心的想法,如果一个数在一个一直往右扩张的区间中,出现多次那么我们只要算最右边的那
个数的贡献就好了,所以我们找出每一个数的上一个数是多少然后使得该位置贡献-1(原来是1),然后现在这个位置+1
然后算答案的时候是sum(a[i].r)-sum(a[i].l-1),sum(x)是树状数组求前缀和,意思为前x个数有多少个不同的的数,
实在不理解可以看看样例 1 1 1 2 3 设cnt[x]表示x这个点的贡献,pre[i]表示第i个数的前一个数的位置
pre[i]={0,1,2,0,0};
当 x=1时 cnt[1]=1,sum[1]=1;
当 x=2时 cnt[1]=1-1=0(pre数组的作用),cnt[2]=1,sum[2]=1;
当 x=3时 cnt[1]=0,cnt[2]=0,cnt[3]=1,sum[3]=1;
当 x=4时 cnt[1]=0,cnt[2]=0,cnt[3]=0,cnt[4]=1,sum[4]=2;
PS:线段树,莫队好像都可以写的样子,莫队可能被卡,线段树相对而言代码多。
#include <algorithm>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <unordered_map>
#include <vector>
#define ll long long int
#define ms(a, b) memset(a, b, sizeof(a))
#define lowbit(x) (x & -x)
#define fi first
#define se second
#define Size(a) int((a).size())
#define ull unsigned long long
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define endl "\n"
#define bug cout << "----acac----" << endl;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
const ll mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxm = 5e3 + 50;
const double eps = 1e-8;
const ll inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1);
int n, m;
int a[maxn];
int b[maxn];
struct segement
{
int l, r;
int id;
} p[maxn];
bool cmp(segement A,segement B)
{
return A.r < B.r;
}
int pre[maxn];
int Next[maxn];
void update(int x,int val)
{
while(x<=n)
{
a[x] += val;
x += lowbit(x);
}
}
int query(int x)
{
int ans = 0;
while(x>0)
{
ans += a[x];
x -= lowbit(x);
}
return ans;
}
int ans[maxn];
int main()
{
IOS;
cin >> n;
for (int i = 1; i <= n;i++)
{
cin >> b[i];
pre[i] = Next[b[i]];
Next[b[i]] = i;
}
cin >> m;
for (int i = 1; i <= m;i++)
{
cin >> p[i].l >> p[i].r;
p[i].id = i;
}
sort(p + 1, p + 1 + m, cmp);
int mx = 1;
for (int i = 1; i <= m;i++)
{
while(mx<=p[i].r&&mx<=n)
{
update(mx, 1);
if(pre[mx])
{
update(pre[mx], -1);
}
mx++;
}
ans[p[i].id] = query(p[i].r) - query(p[i].l - 1);
}
for (int i = 1; i <= m;i++)
{
cout << ans[i] << endl;
}
return 0;
}