洛谷P1972HH的项链 题解
作者:互联网
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。
有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
题目分析
这个问题是一个区间求值的问题,数据范围辣么大,自然而然的想到利用前缀和的思想
BUT 这道题并不是简单的区间和,而是区间内所有数值的种类数
也就是说,一段区间内重复的元素只有其中一个对答案的贡献为 \(1\),其他所有都不做贡献
那么我们就从每种相同的元素选出一个代表,代表做出 \(1\) 的贡献,而其他元素都不做贡献不就行了?
(说起来容易,到底怎么做呀!)
那我们到底选 哪一位幸运观众 哪一个数来当我们的代表元素哩?
是第一个?第二个?最后一个?还是都可以?
答案是:(刮刮乐——>)最后一个
为什么是最后一个呢?
别急,听我仔细向您道来~
如果我们不选一段区间里的重复元素中的最后一个作为代表元素
那么,如果正好有一段区间,只包含这些元素中的最后那一个,答案本应该加上 \(1\),但我们却加不上,因为那 \(1\) 的贡献在别人身上
所以我们应该把所有重复元素贡献集中到最后一个
当然不是全部的最后一个,是会随着从左到右考虑而变化的
之后,我们就有了如下思路:
-
处理输入
-
预处理出对于数列中的每一个元素 \(x\),上一个 \(x\) 出现的位置
-
离线存储所有询问,并按右端点从小到大排序
-
从 \(1\) 到 \(n\) 枚举数列中的每一数,把上一次出现他的位置的贡献置为 \(0\)(-1),并把当前位置贡献置为 \(1\)(+1)
-
用简单好写常数小空间不大的树状数组维护区间和
-
如果当前位置是某些查询的右端点,就查询一下贡献数列的区间 \([l_i,r_i]\) 的和作为这次询问的答案
-
输出答案
(输入量巨大,记得加快读快出)
思路分析完毕,上代码:
AC代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,m;
int c[N];
int l[N],o[N];
int a[N];
void read(int& x)
{
x=0;
int f=1;
char c;
c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
x*=f;
}
void write(int x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct Q{
int l,r;
int id;
}q[N];
int lowbit(int x)
{
return x&-x;
}
void update(int x,int k)
{
while(x<=n)
{
c[x]+=k;
x+=lowbit(x);
}
}
int query(int x)
{
int res=0;
while(x)
{
res+=c[x];
x-=lowbit(x);
}
return res;
}
bool cmp(Q A,Q B)
{
return A.r<B.r;
}
int main()
{
read(n);
for(int i=1;i<=n;i++)
{
int x;
read(x);
o[i]=l[x];
l[x]=i;
}
read(m);
for(int i=1;i<=m;i++)
{
read(q[i].l),read(q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int p=1;
for(int i=1;i<=n;i++)
{
if(o[i])
update(o[i],-1);
update(i,1);
while(i==q[p].r)
{
a[q[p].id]=query(q[p].r)-query(q[p].l-1);
p++;
}
}
for(int i=1;i<=m;i++)
write(a[i]),puts("");
return 0;
}
完结撒花?
不,还没有完全结束
我们刚才证明了把贡献放在除了最后一个的其他位置不能得到这道题的答案
那他能得到什么题的答案呢?
刚才把代表元素定位最后一个,就可以得到区间内出现次数大于等于一的数的种类
那如果我们选倒数第二个,是不是就可以得到区间内出现次数大于等于二的数的种类
聪明!当然可以!
补充完这一点,这题就彻底做完了
白白ヾ(•ω•`)o~~~
标签:洛谷,贝壳,P1972HH,int,题解,元素,贡献,项链,区间 来源: https://www.cnblogs.com/Orange-Star/p/16593354.html