Codeforces 38 G. Queue
問題
n人の人が以下のようなルールで列に並ぶ。
- i番目の人が来て、列の最後尾に加わる。i番目の人は重要度a[i]と、常識度c[i]を持っている。
- 一つ前の人の重要度a[i-1]が、自分の重要度より低かったら、その人前へ割り込む。
- 割り込みはc[i]回だけできる。
n人の人が全て並び終わった後、列はどうなっているか答えよ。
制約条件
n≦10^5
a[i]は1からnの順列になっている
方針
平方分割による。
列をsqrt(n)くらいずつのグループに分割して持っておき、グループごとに飛ばせるかを見ることで、
時間計算量O(n^1.5)くらいで全体のクエリを処理することができる。
グループは人数がだんだん不均一になってくるので、
挿入がsqrt(n)回くらいおこった後にグループを均等に更新してやる。
これで全体の時間計算量が最悪でもO(n^1.5)になる。
ソースコード
const int SZ=300; int n; vector<vi> bucket; int mx[100000/SZ+1]; int A[100000],id[100001]; void run(){ scanf("%d",&n); bucket.resize(1); rep(i,n){ int a,c; scanf("%d%d",&a,&c); id[a]=i+1; int p=bucket.size()-1; for(;c>0&&p>0;p--){ if(mx[p]>a||bucket[p].size()>c)break; c-=bucket[p].size(); } int q=bucket[p].size(); for(;c>0&&q>0;q--,c--){ if(bucket[p][q-1]>a)break; } bucket[p].insert(bucket[p].begin()+q,a); mx[p]=max(mx[p],a); if(i%SZ==SZ-1||i==n-1){ int l=0; rep(j,bucket.size())rep(k,bucket[j].size())A[l++]=bucket[j][k]; bucket.clear(); bucket.resize((l+SZ-1)/SZ); rep(j,(l+SZ-1)/SZ)mx[j]=0; rep(j,l){ bucket[j/SZ].pb(A[j]); mx[j/SZ]=max(mx[j/SZ],A[j]); } } } rep(i,n)printf("%d%c",id[A[i]],i==n-1?'\n':' '); }