BZOJ4241 历史研究

6 篇文章 0 订阅

一眼觉得是莫队,发现删除不是很好搞,于是上回滚莫队直接搞过

回滚莫队用于处理难以删除但是易于添加(其实易于删除难以添加也可以,但是没见过这样题-_-)的莫队,排序照常,如果左右端点在同一块直接暴力,这部分最多n sqrt n,否则把左端点在一块的一起处理,清空莫队,然后直接令莫队左端点在块尾,这部分n sqrtn,右端点照常走,这部分n sqrtn ,左端点每次走的时候记录更改了哪些量,走到地方记录完答案把修改回滚回去,这部分也是n sqrtn,所以复杂度还是根号的,但是把删除干掉了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<ctime>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<bitset>
#include<map>
using namespace std;
#define MAXN 100010
#define MAXM 100010
#define INF 1000000000
#define MOD 1000000007
#define ll long long
#define eps 1e-8
char xB[1<<15],*xS=xB,*xT=xB;
#define getc() (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline int read()
{
int x=0,f=1;char xch=getc();
while(xch<'0'|xch>'9'){if(xch=='-')f=-1;xch=getc();}
while(xch>='0'&&xch<='9'){x=x*10+xch-'0';xch=getc();}
return x*f;
}
struct que{
	int l;
	int r;
	int num;
	int k;
	friend bool operator <(que x,que y){
		return x.k!=y.k?x.k<y.k:x.r<y.r;
	}
};
int siz;
que q[MAXM];
int a[MAXN];
int cnt[MAXN];
ll ans[MAXN];
int num[MAXN];
int visc[MAXN];
ll ANS;
map<int,int>h;
int tls[MAXN],tln,mx;
int g[MAXN];
int n,m;
int L,R;
int T;
int *st[MAXN];
int stv[MAXN],tp;
ll *sta[MAXN];
ll stva[MAXN];
int tpa;
void roolback(){
	while(tp){
		(*st[tp])=stv[tp];
		tp--;
	}
	while(tpa){
		(*sta[tpa])=stva[tpa];
		tpa--;
	}
}
int main(){
	int i,j;
	n=read();
	m=read();
	for(i=1;i<=n;i++){
		a[i]=read();
		tls[++tln]=a[i];
	}
	sort(tls+1,tls+tln+1);
	tls[0]=-INF;
	for(i=1;i<=tln;i++){
		if(tls[i]!=tls[i-1]){
			h[tls[i]]=++mx;
			g[mx]=tls[i];
		}
	}
	for(i=1;i<=n;i++){
		a[i]=h[a[i]];
	}
	siz=sqrt(n);
	for(i=1;i<=m;i++){
		q[i].l=read();
		q[i].r=read();
		q[i].k=(q[i].l-1)/siz+1;
		q[i].num=i;
	}
	sort(q+1,q+m+1);
	for(i=1;i<=m;i++){
		
		if(q[i].k!=q[i-1].k){
			//<<"^^^"<<endl;
			T++;
			L=siz*q[i].k+1;
			R=L-1;
			ANS=0;
		}
		//<<q[i].l<<'!'<<q[i].r<<endl;
		//<<L<<' '<<R<<endl;
		//<<cnt[2]<<"&"<<endl;
		if(q[i].r<L){
			//<<"@"<<endl;
			ANS=0;
			for(j=q[i].l;j<=q[i].r;j++){
				if(visc[a[j]]!=T){
					cnt[a[j]]=0;
				}
				visc[a[j]]=T;
				cnt[a[j]]++;
				if((ll)g[a[j]]*cnt[a[j]]>ANS){
					ANS=(ll)g[a[j]]*cnt[a[j]];
				}
			}
			ans[q[i].num]=ANS;
			T++;
			ANS=0;
			continue ;
		}
		while(R<q[i].r){
			//<<"#"<<endl;
			R++;
			if(visc[a[R]]!=T){
				cnt[a[R]]=0;
			}
			visc[a[R]]=T;
			cnt[a[R]]++;
			
			if((ll)g[a[R]]*cnt[a[R]]>ANS){
				ANS=(ll)g[a[R]]*cnt[a[R]];
			}
		}
		while(L>q[i].l){
			//<<"!"<<endl;
			L--;
			if(visc[a[L]]!=T){
				cnt[a[L]]=0;
			}
			st[++tp]=&visc[a[L]];
			stv[tp]=visc[a[L]];
			visc[a[L]]=T;
			st[++tp]=&cnt[a[L]];
			stv[tp]=cnt[a[L]];
			cnt[a[L]]++;
			
			if((ll)g[a[L]]*cnt[a[L]]>ANS){
				sta[++tpa]=&ANS;
				stva[tpa]=ANS;
				ANS=(ll)g[a[L]]*cnt[a[L]];
			}
		}
		ans[q[i].num]=ANS;
		roolback();
		L=siz*q[i].k+1;
	}
	for(i=1;i<=m;i++){
		printf("%lld\n",ans[i]);
	}
	return 0;
}

/*
5 5
2 2 2 1 2 
4 4
1 1
3 4
1 1
1 5



*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值