件名の説明:
長さの文字列を考えると(N- \)\シーケンスを、ある\(Q \)クエリ、番号の各への問い合わせ\((I、J)\) 、間隔を見つける\([I、J] \ ) どのように多くの異なった数字は持っています
これは私がMoのチームとしていた問題であり、
我々はすべて知っている、チームはMoのです暴力がん形而上学非常に便利アルゴリズム(データ構造の無い他のセット)、範囲の問題の多くの周りにだますことができます。
psの私はこれを介していたブログ間違った場所を理解することがあれば、学校から、だけでなく、dalao補正を探します
話題に:
Moのチームの後ので、その優れた複雑さを確保し、左右のエンドポイントを移動することによって、あなたの答えを変更するにはソートアルゴリズムお願いします。
クエリをソートするとき、我々は、ブロックを使用するために考えた:
我々は、全区間分割\(\ SQRT {N} \ ) ブロック。
ソート時に、同じブロック内の左端ポイント場合には降順右端を押すであろう。そうでなければ、ブロックの左端が降順。
これは、各エンドポイントの最大移動を確保\(\ SQRT {N} \ ) グリッド、したがって複雑さを確保します。
friend bool operator < (qus a,qus b){
return k[a.l]==k[b.l]?a.r<b.r:k[a.l]<k[b.l];
}
そして、あなたは、ソート、分類は、あなたが形而上学GUGU区のコードをスピードアップすることができ、奇数と偶数のブロックに分類することができ、通常のソートインチ
friend bool operator < (qus a,qus b){
return k[a.l]^k[b.l]?k[a.l]<k[b.l]:(k[a.l]&1?a.r<b.r:a.r>b.r);
}
つまり後Add
とDel
機能は移動中に答えを更新するために使用されます。
NUMは、現在の間隔で記録\([L、R] \ ) 、デジタルタイプの(cnt_x \)\表示されxは回数を記録します。
第一のPOS番号に添加した場合、この番号は最初にこの間隔に登場した場合、合計数は1だけ増加されるであろう。
void Add(int pos){
if(!cnt[a[pos]]) ++num;
++cnt[a[pos]];
}
あなたが最初のPOS番号を削除すると、この番号が削除された区間に表示されていない場合、合計数はマイナス1になります。
void Del(int pos){
--cnt[a[pos]];
if(!cnt[a[pos]]) --num;
}
そして、それは、エンドポイントの周りに転送されます。
左、答え未満の左端点の現在の点が点が削除された場合、右側のポイントと左、
左の現在の点が、左端点は答えよりも大きい場合、左点の左端点が追加され;
現在の右端点は、点が正解よりも大きい場合、ポイントが削除され、左側右端は、
現在の右点場合、答えは、より少ない右端点よりも右右端、およびポイントにその時点追加しました。
(これは、早口言葉ではありません)
while(L<q[i].l) Del(L++);
while(L>q[i].l) Add(--L);
while(R<q[i].r) Add(++R);
while(R>q[i].r) Del(R--);
最後に、統計への回答では、最初に入力した順に出力だけで罰金。
コードは次のように(風がかなり醜いコード)です。
#include<bits/stdc++.h>
#define rint register int
using namespace std;
inline int read(){
int s=0,f=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar();
return f?s:-s;
}
int n,a[30010],cnt[1000010],num=0,Q;
int k[1010],ks,ans[200010];
struct qus{
int l,r,id;
friend bool operator < (qus a,qus b){
return k[a.l]^k[b.l]?k[a.l]<k[b.l]:(k[a.l]&1?a.r<b.r:a.r>b.r);
}
}q[200010];
void Del(int pos){
--cnt[a[pos]];
if(!cnt[a[pos]]) --num;
}
void Add(int pos){
if(!cnt[a[pos]]) ++num;
++cnt[a[pos]];
}
int main(){
n=read(); ks=sqrt(n);
for(rint i=1;i<=n;++i) a[i]=read();
for(rint i=1;i<=n;++i) k[i]=(i-1)/ks+1;
Q=read();
for(rint i=1;i<=Q;++i){
q[i].l=read();
q[i].r=read();
q[i].id=i;
}
sort(q+1,q+1+Q);
int L=1,R=0;
for(rint i=1;i<=Q;++i){
while(L<q[i].l) Del(L++);
while(L>q[i].l) Add(--L);
while(R<q[i].r) Add(++R);
while(R>q[i].r) Del(R--);
ans[q[i].id]=num;
}
for(rint i=1;i<=Q;++i)
printf("%d\n",ans[i]);
return 0;
}
GUGU区〜