「JOISC 2014 Day1」 历史研究
「JOISC 2014 Day1」 历史研究
Solution
子任务2
暴力,用\(cnt\)记录每种权值出现次数。
子任务3
这不是一个尺取吗...
然后用multiset维护当前的区间,动态加,删点即可。
子任务4
目前可以支持在\(o(log(n) )\)的时间里动态加,删单点了。
容易想到莫队。
直接用multiset维护复杂度\(o(n \sqrt n log(n))\)。(一脸不可过)
稍微优化一下
若使用cnt记录的话,是没法很好的删点的。
对于目前要处理的块\([l,r]\),询问右端点单调,没有删点的操作,需要删点操作的是左端点的块内移动。
事实上,左端点的块内移动可以直接改为加入需要用到的点。
\(cnt\)统计\(r+1\)以后的点 ,cnt本身维护一个最大值MAX。加入块内的点 时,MAX不变,维护一个ANS。
这样就不需要删点了(加入的 块内的点 回滚一下即可)。
最终复杂度\(o(n \sqrt n)\)
Code
#include<bits/stdc++.h>
#define rep(q,a,b) for(int q=a,q##_end_=b;q<=q##_end_;++q)
#define dep(q,a,b) for(int q=a,q##_end_=b;q>=q##_end_;--q)
#define mem(a,b) memset(a,b,sizeof a )
#define debug(a) cerr<<#a<<' '<<a<<"___"<<endl
using namespace std;
void in(int &r) {
static char c;
r=0;
while(c=getchar(),!isdigit(c));
do r=(r<<1)+(r<<3)+(c^48);
while(c=getchar(),isdigit(c));
}
const int mn=100005;
int val[mn],mid[mn],n,Q;
int cnt[mn];
namespace something_only_for_fc{
void solve(){
int l,r;
while(Q--){
in(l),in(r);
long long Max=0;
rep(q,l,r)++cnt[val[q]];
rep(q,l,r)Max=max(Max,1LL*cnt[val[q]]*mid[val[q]]);
rep(q,l,r)--cnt[val[q]];
printf("%lld\n",Max);
}
}
}
struct node{
int l,r,id;
bool operator <(const node &A)const{
return l==A.l?r<A.r:l<A.l;
}
}qr[mn];
long long ans[mn];
namespace something_value_25pts{
multiset<long long> have_val;
multiset<long long>::iterator it;
void remove(long long v){
it=have_val.find(v);
if(it!=have_val.end())have_val.erase(it);
}
long long Max(){
it=have_val.end(),--it;
return (*it);
}
void solve(){
int now=1;
int l=1;
for(int r=1;r<=n;++r){
if(cnt[val[r]])remove(1LL*cnt[val[r]]*mid[val[r]]);
++cnt[val[r]];
have_val.insert(1LL*cnt[val[r]]*mid[val[r]]);
if(now<=Q&&r==qr[now].r){
while(l<qr[now].l){
remove(1LL*cnt[val[l]]*mid[val[l]]);
--cnt[val[l]];
if(cnt[val[l]])have_val.insert(1LL*cnt[val[l]]*mid[val[l]]);
++l;
}
ans[qr[now].id]=Max();
++now;
}
}
rep(q,1,Q)printf("%lld\n",ans[q]);
}
}
bool pts_25_check(){
rep(q,2,Q)if(qr[q].l==qr[q-1].l)return 0;
return 1;
}
namespace something_just_for_fun{
vector<node> son[400];
long long Max,an;
void add(int v){
++cnt[v];
Max=max(Max,1LL*cnt[v]*mid[v]);
}
void mid_add(int v){
++cnt[v];
an=max(an,1LL*cnt[v]*mid[v]);
}
int now_r;
void move(int to){
rep(q,now_r+1,to)add(val[q]);
now_r=to;
}
bool cmp(node a,node b){
return a.r<b.r;
}
void get(int x,int now){
if(!son[x].size())return;
now_r=now,Max=0;
rep(q,1,n)cnt[q]=0;
sort(son[x].begin(),son[x].end(),cmp);
rep(q,0,(int)son[x].size()-1){
if(son[x][q].r<=now){
an=0;
rep(w,son[x][q].l,son[x][q].r)mid_add(val[w]);
rep(w,son[x][q].l,son[x][q].r)--cnt[val[w]];
}else{
move(son[x][q].r);
an=Max;
rep(w,son[x][q].l,now)mid_add(val[w]);
rep(w,son[x][q].l,now)--cnt[val[w]];
}
ans[son[x][q].id]=an;
}
}
void solve(){
int K=sqrt(n)+1;
int lim=n/K;
rep(q,1,Q)son[qr[q].l/K].push_back(qr[q]);
rep(q,0,lim)get(q,min(n,(q+1)*K-1));
rep(q,1,Q)printf("%lld\n",ans[q]);
}
}
int main(){
freopen("history.in","r",stdin);
freopen("history.out","w",stdout);
in(n),in(Q);
rep(q,1,n)in(val[q]),mid[q]=val[q];
sort(mid+1,mid+n+1);
rep(q,1,n)val[q]=lower_bound(mid+1,mid+n+1,val[q])-mid;
if(n<=5000&&Q<=5000)something_only_for_fc::solve();
else{
rep(q,1,Q)in(qr[q].l),in(qr[q].r),qr[q].id=q;
sort(qr+1,qr+Q+1);
if(pts_25_check())something_value_25pts::solve();
else something_just_for_fun::solve();
}
return 0;
}