[解説] BZOJ4241:歴史的研究(デビルチームチェンジMO)
本当に良い質問ああ
問題の意味
あなたのクエリー配列とグループ番号(オフライン)を得、あなたにこの間隔尋ねる\(\最大\を) {要素番号を表示されます(\タイムズ\)\要素の重量}
IOI国--JOIが、最近、日記のコピーを受信した最初の人物歴史研究教授は、IOIが書いた国の古代の住民であると考えられています。教授JOI古代の生活IOIの国を研究するために、この日記を渡すためには、調査日記に記述されているイベントを開始しました。
日記は毎日について、N日間連続の発生時間を記録します。
イベントポイントの種類があります。イベントの日I(1 <= iが<= N)型は、整数西、西イベントの大きい、大きなサイズで表される発生しました。
教授JOIは、以下の方法により、これらの日記を分析することにしました:
の分析など日間連続の\ 1. [日記期間
\ 2. tにイベント型tの重要性*(今回のイベントのトン数の重要性)
\ 3.イベントのすべての種類の重要性を、計算した最大出力で
今、あなたはヘルパー教授チェン徐分析を行うように求められ、各区間の分析が与えられている、あなたは出力に重要度が最大を必要としています。
問題の解決策
要素の数と範囲は、最初の何のMoチーム検討し、関連する表示されます。Moのチームは、要素の数は、今あなたが要素を知って、表示され維持(\回\)\マックス右。
あなたのレコードはモザンビークチームに追加されることがあります番号が答え、適切に(してください意味:最大値を維持することが可能であるans=max(ans,(ll)data[i]*cnt[i]);
)を、それはあなたが(あなたのチームは、別のデータ構造が機能しない設定しないでください、削除する要素のためではない、残業)ので、私たちのMOチームが唯一の要素を追加サポートしています。
Moのチームが唯一の要素を追加することができますか?つまり、魔法のMoチームを変更することはできませんか?
ブロックの合計尋ねますMoのチームに従って同様に尋ねる考えてみましょう\(O(\ sqrtのN) \) ブロックごと問い合わせ互いに独立を。各尋ね1、及びMo同じチームのために、順序右ポイントを昇順にソート。
ポイントを取得する方法を求める権利を考えてみましょう:私たちは、増加する権利へのポインタを提唱している、維持\を(CNT [] \)の配列。そのような複雑さは、\(O(N)\)ポインタがロールバックされていないので、。
その後、左ポイントと取得する方法を考えてみましょう。直接暴力の統計情報を。前に、我々は右の点から現在のブロックの右側にポインタをしましょう。今右端ブロックの右側を指す\(CNTは、[] \)を得ることができます。
しかし、我々はまだ左に右のポイントをブロック貢献。この部分に先立ち\(CNT [] \)は、直接に基づいて暴力統計あなたは答えを数えることができるようにのみ、モザンビークチームに要素を追加がまだあるので、。それはチームがMoのブロックを要求する方法であるため、各チャレンジのために、暴力統計の複雑さはすぎない\(O(\ N- SQRT)\) 。
しかし、それは間隔がより小さい求めることができる(\ N- SQRT \)\、我々は状況、彼はプロセスに直接読み込む問い合わせのこの部分を防ぐために、国境を議論します。
複雑さを分析します。
- 各問い合わせのために、暴力の統計的部分である\()\ O(\ SQRT N-)の複雑さの、この部分\(O(N \ SQRT N )\)
- ブロック毎に、右にポインタが移動\(O(N)\)の複合体の一部であり、\(O(N \ SQRT N )\)
- 小さな、暴力的な統計情報の種類を尋ね\(O(nは\ sqrtのN )\) の
- 実際には、離散することが、私たちは、ディスクリート、直接ハッシュのサイズに従う必要はありません\(O(N)を\) 。(bzoj専用マップで、サポートされていません)
全体的に複雑\(O(nは\ sqrtのN )\)
この質問は、実際に書き込みをする方法に関する情報提供のみの操作の追加/削除をサポートMoのチームをアルゴリズムのを。普遍性は非常に広いです。
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
struct E{
int l,r,id;
E(){l=r=0;}
E(const int&a,const int&b,const int&c){l=a;r=b;id=c;}
inline bool operator <(const E&a)const{return r<a.r;}
};
const int maxn=1e5+5;
int cnt0,n,m,N;
int be[maxn],cnt[maxn],arc[maxn],data[maxn];
ll ans[maxn],now;
map<int,int> s0;
vector<int> s;
vector<E> ve[355];
inline void add(const int&pos,const int&tag){
cnt[data[pos]]+=tag;
if(1ll*cnt[data[pos]]*arc[data[pos]]>now) now=1ll*cnt[data[pos]]*arc[data[pos]];
}
int main(){
n=qr(); m=qr(); N=sqrt(n-1)+1;
for(register int t=1;t<=n;++t){
data[t]=qr();
if(s0.find(data[t])==s0.end()) s0[data[t]]=++cnt0,arc[cnt0]=data[t];
data[t]=s0[data[t]];
}
for(register int t=1;t<=n;++t) be[t]=(t-1)/N+1;
for(register int t=1,t1,t2;t<=m;++t) {
t1=qr(),t2=qr();
if(t2-t1-5<N){
now=0;
for(register int t=t1;t<=t2;++t) add(t,1),s.push_back(data[t]);
for(register int t=0,ed=s.size();t<ed;++t) --cnt[s[t]];
ans[t]=now; s.clear();
continue;
}
ve[be[t1]].push_back(E(t1,t2,t));
}
for(register int t=1;t<=be[n];++t){
if(ve[t].empty()) continue;
memset(cnt,0,sizeof cnt);
sort(ve[t].begin(),ve[t].end());
int R=N*t,st=R; ll tnow=now=0;
for(register int i=0,ed=ve[t].size();i<ed;++i){
register E f=ve[t][i];
while(R<f.r) add(++R,1);
tnow=now;
for(register int t=st;t>=f.l;--t) add(t,1),s.push_back(data[t]);
for(register int t=0,ed=s.size();t<ed;++t) --cnt[s[t]];
ans[f.id]=now; now=tnow; s.clear();
}
}
for(register int t=1;t<=m;++t) printf("%lld\n",ans[t]);
return 0;
}