タイトル
トピックリンク:https://www.luogu.com.cn/problem/P1972
で構成される美しい貝殻の様々なからHH文字列のネックレス。HHはので、すべての散歩の後、彼は、彼らが表現の意味を考えて、しばらくアウトシェルに無料になります、幸運をもたらすとは異なるシェルを信じています。HHは、常に新しいシェルを集めるので、彼は長いネックレスを取得しています。
シェルの一定期間、どのように多くの異なったシェルを含む:ある日、彼は突然問題を提起しますか?ネックレスは長すぎるので、この質問は......答えることは困難です。そこで彼は、この問題を解決するために、賢明なあなたを助けるために持っていました。
思考
チームを書き込む前のMoである\(O(N \ SQRT { N})\) アルゴリズムが。今データは、書き込みに戻ってくる、その後、強化してきた\(O(N \ Nログ )\) アルゴリズムを。
束のために考えてみましょう(= xは\ R_iと)\尋ねた(I \)\、我々が見つかりました。その内の数字は、以下の場合に\(\ [、X 1]は ) 何回か登場し、その後、より以上の最大値を取る(\ X \)デジタル位置が明確に最善です。
私たちは私たちが知っている限り、ポイントの束を依頼することと同じ権利を扱っているので、\([1、x]はを\ ) どこのことができます。各桁の最終的な位置に表示されます。
ツリーアレイ、プロセス確立\(X = I \)を、アレイツリー内の位置\(J \)は間隔を表し\([1、i]の\ ) 、位置(\ \ J)の上番号である場合(これは、最後の発生である\(C [I] \で\ {0,1 \} \) )。その後、クエリの時間\([L、X] \) 、答えは\(\ SUM _ ^ {X} L {I} = C [I] \) 。フェンウィックツリー\(O(\ nはログ) \) を取得。
位置から\(I \)の位置の問い合わせに転送(I + 1 \)\問い合わせ時に、我々\([I + 1] \) アレイ上のツリーの最初の発生の位置がクリアされ、位置\(I + 1 \)は 1標識。それでも\(O(\ nはログ)
\) 時間複雑\(O(N \ Nログ )\)
コード
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=1000010;
int n,m,a[N],last[N],ans[N];
struct ASK
{
int l,r,id;
}ask[N];
struct BIT
{
int c[N];
int ask(int x)
{
int sum=0;
for (int i=x;i;i-=i&-i)
sum+=c[i];
return sum;
}
void add(int x,int val)
{
if (!x) return;
for (int i=x;i<=n;i+=i&-i)
c[i]+=val;
}
}bit;
bool cmp(ASK x,ASK y)
{
return x.r<y.r;
}
int read()
{
int d=0,f=1; char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d*f;
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
a[i]=read();
m=read();
for (int i=1;i<=m;i++)
ask[i].l=read(),ask[i].r=read(),ask[i].id=i;
sort(ask+1,ask+1+m,cmp);
for (int i=1;i<=m;i++)
{
for (int j=ask[i-1].r+1;j<=ask[i].r;j++)
bit.add(last[a[j]],-1),bit.add(j,1),last[a[j]]=j;
ans[ask[i].id]=bit.ask(ask[i].r)-bit.ask(ask[i].l-1);
}
for (int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}