P1972 [SDOI2009]HH的项链
Posted acmloser
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1972 [SDOI2009]HH的项链相关的知识,希望对你有一定的参考价值。
原题链接
考察:树状数组
思路:
本蒟蒻是完全想不到怎么写....参考大佬题解.
求种类数,可以处理的方法一个是针对询问实时加入数.但是这样一定会TLE,然后不好求重复的数字数.
参考大佬的题解,正解做法是i从1~n实时加入数,到询问的右端点求ans.这里与求逆序对的方法不同的是tr[i]表示下标为i时有多少个有效的数字.即add(i,1)表示下标为1处有效数字+1.
然后就是重复数字如何求.对于每一个询问,我们优先处理右端点靠前的.每一个重复数字,我们只在最右端add(i,1).之前的add(pre,-1).看代码吧,这题解思路基本参考大佬的.
为什么以右端点排序呢?如果左端点靠前的区间太长,后面的区间又较短,导致重复数字的有效位被更新到后面导致答案错误.
如果以左端点排序就需要从后往前处理,否则时间复杂度降不下来
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N = 1000010;
int a[N],n,m,tr[N],c[N],ans[N];
struct Query{
int l,r,id,ans;
bool operator<(Query q){
if(this->r!=q.r) return this->r<q.r;
return this->l<q.l;
}
}q[N];
int lowbit(int x)
{
return x&-x;
}
void add(int k,int x)
{
for(int i=k;i<=n;i+=lowbit(i)) tr[i]+=x;
}
int ask(int x)
{
int res = 0;
for(int i=x;i;i-=lowbit(i)) res+=tr[i];
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id = i;
}
sort(q+1,q+m+1);
for(int i=1,j=1;i<=n;i++)
{
if(c[a[i]]) add(c[a[i]],-1);
add(i,1);
c[a[i]] = i;
while(q[j].r==i)
{
q[j].ans = ask(q[j].r)-ask(q[j].l-1);
j++;
}
}
for(int i=1;i<=m;i++) ans[q[i].id] = q[i].ans;
for(int i=1;i<=m;i++) printf("%d\\n",ans[i]);
return 0;
}
以上是关于P1972 [SDOI2009]HH的项链的主要内容,如果未能解决你的问题,请参考以下文章