(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
当莫队删数困难时,考虑“只增莫队”
增数处理很容易,删数处理却较难处理。
对于[L, R]区间的询问:假设L所处块的右端点为Rs,从Rs向两边增数!
当L所处块相同时,R是只增的。L的变化肯定也是从Rs增数过来的。
你可能会说,虽然说L在同一块内,但是他们大小是没有规律的。没错,所以在一次询问完成后,要把L还原到Rs,这样下一次还会是增数处理。
复杂度玄学:
O
(
1
e
5
能
过
)
O(1e5能过)
O(1e5能过)
AC代码
8002ms
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+7;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
int n,m;
LL ans;
int ar[N],belong[N],br[N],now[N];
LL Ans[N];
int cnt[N],in_left[N];
struct lp{
int l,r,id;
}cw[N];
bool cmp(const lp &a,const lp &b){
if(belong[a.l]==belong[b.l]){
return a.r<b.r;
}
return belong[a.l]<belong[b.l];
}
void update_left(int x,int f){
cnt[now[x]]++;
if((cnt[now[x]])*1LL*ar[x]>ans){
ans=(cnt[now[x]])*1LL*ar[x];
}
}
int main(){
scanf("%d%d",&n,&m);
int block=(int)sqrt(n*1.0);
for(int i=1;i<=n;++i){
scanf("%d",&ar[i]);
br[i]=ar[i];
belong[i]=(i-1)/block+1;
}
sort(br+1,br+1+n);
int k=1;
for(int i=2;i<=n;++i){
if(br[i]!=br[i-1]){
br[++k]=br[i];
}
}
for(int i=1;i<=n;++i){
now[i]=lower_bound(br+1,br+1+n,ar[i])-br;
}
for(int i=1;i<=m;++i){
scanf("%d%d",&cw[i].l,&cw[i].r);
cw[i].id=i;
}
memset(cnt,0,sizeof(cnt));
sort(cw+1,cw+m+1,cmp);
int L=1,R=0,limit;
LL last_ans=0;
ans=0;cw[0].l=0;belong[0]=0;
for(int i=1;i<=m;++i){
if(belong[cw[i-1].l]!=belong[cw[i].l]){
memset(cnt,0,sizeof(cnt));
limit=belong[cw[i].l]*block;
R=limit;
ans=last_ans=0;
}
L=min(limit+1,cw[i].r+1);
while(R<cw[i].r){
R++;ans=max((++cnt[now[R]])*1LL*ar[R],ans);
}
last_ans=ans;
while(L>cw[i].l)update_left(--L,1);
Ans[cw[i].id]=ans;
for(int j=L;j<=cw[i].r&&j<=limit;++j){
cnt[now[j]]--;
}
ans=last_ans;
}
for(int i=1;i<=m;++i){
printf("%lld\n",Ans[i] );
}
return 0;
}
题目
Description
IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
日记中记录了连续N天发生的时间,大约每天发生一件。
事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
JOI教授决定用如下的方法分析这些日记:
- 选择日记中连续的一些天作为分析的时间段
- 事件种类t的重要度为t*(这段时间内重要度为t的事件数)
- 计算出所有事件种类的重要度,输出其中的最大值
现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。
Input
第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1…XN,Xi表示第i天发生的事件的种类
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。
Output
输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度
Sample Input
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
Sample Output
9
8
8
16
16
Hint
1<=N<=10^5
1<=Q<=10^5
1<=Xi<=10^9 (1<=i<=N)
Source
JOI 2013~2014 春季training合宿 竞技1 By PoPoQQQ
以前写过的代码1:9479ms
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+7;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
int n,m,ar[N],belong[N],br[N],now[N];
LL ans,Ans[N];
int cnt[N],in_left[N];
struct lp{
int l,r,id;
}cw[N];
bool cmp(const lp &a,const lp &b){
if(belong[a.l]==belong[b.l]){
return a.r<b.r;
}
return belong[a.l]<belong[b.l];
}
void update_left(int x,int f){
in_left[now[x]]++;
if((in_left[now[x]]+cnt[now[x]])*1LL*ar[x]>ans){
ans=(in_left[now[x]]+cnt[now[x]])*1LL*ar[x];
}
}
int main(){
scanf("%d%d",&n,&m);
int sz=(int)sqrt(n*1.0);
for(int i=1;i<=n;++i){
scanf("%d",&ar[i]);
br[i]=ar[i];
belong[i]=(i-1)/sz+1;
}
sort(br+1,br+1+n);
int k=1;
for(int i=2;i<=n;++i){
if(br[i]!=br[i-1]){
br[++k]=br[i];
}
}
for(int i=1;i<=n;++i){
now[i]=lower_bound(br+1,br+1+n,ar[i])-br;
}
for(int i=1;i<=m;++i){
scanf("%d%d",&cw[i].l,&cw[i].r);
cw[i].id=i;
}
sort(cw+1,cw+m+1,cmp);
int L=1,R=0,tmd;
LL tmp=0;
ans=0;cw[0].l=0;belong[0]=0;
for(int i=1;i<=m;++i){
if(belong[cw[i-1].l]!=belong[cw[i].l]){
memset(cnt,0,sizeof(cnt));
tmd=belong[cw[i].l]*sz;
R=tmd;
ans=tmp=0;
}
L=min(tmd+1,cw[i].r+1);
while(L>cw[i].l)update_left(--L,1);
while(R<cw[i].r){
R++;
tmp=max((++cnt[now[R]])*1LL*ar[R],tmp);
ans=max(ans,(cnt[now[R]]+in_left[now[R]])*1LL*ar[R]);
}
Ans[cw[i].id]=ans;
for(int j=L;j<=cw[i].r&&j<=tmd;++j){
in_left[now[j]]--;
}
ans=tmp;
}
for(int i=1;i<=m;++i){
printf("%lld\n",Ans[i] );
}
return 0;
}
以前写过的代码2: 10946ms
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+7;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
int n,m,cnt[N],ar[N],br[N],now[N],belong[N],cnt_L,cnt_R;
LL ans,tmp_ans,Ans[N];
struct lp{
int l,r,id;
}cw[N],liu[N];
bool cmp(const lp &a,const lp &b){
if(belong[a.l]==belong[b.l]){
return a.r<b.r;
}
return belong[a.l]<belong[b.l];
}
bool cmp2(const lp &a,const lp &b){
if(a.l!=b.l)return a.l<b.l;
return a.r<b.r;
}
void update(int x,int f){
cnt[now[x]]+=f;
cnt_L=min(cnt_L,now[x]);
cnt_R=max(cnt_R,now[x]);
if(ans<(cnt[now[x]]*1LL*ar[x])&&f==1){
ans=(cnt[now[x]]*1LL*ar[x]);
}
}
int main(){
scanf("%d%d",&n,&m);
int sz=(int)sqrt(n*1.0);
for(int i=1;i<=n;++i){
scanf("%d",&ar[i]);
br[i]=ar[i];
belong[i]=(i-1)/sz+1;
}
sort(br+1,br+1+n);
int k=1;
for(int i=2;i<=n;++i){
if(br[i]!=br[i-1]){
br[++k]=br[i];
}
}
for(int i=1;i<=n;++i){
now[i]=lower_bound(br+1,br+1+k,ar[i])-br;
}
for(int i=1;i<=m;++i){
scanf("%d%d",&cw[i].l,&cw[i].r);
cw[i].id=i;
}
sort(cw+1,cw+m+1,cmp);
int L=0,R,liu_k=0;
cnt_L=0,cnt_R=0;
ans=tmp_ans=0;cw[0].l=liu[0].l=0;
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=m;++i){
if(belong[cw[i].l]==belong[cw[i].r]){
liu[++liu_k].l=cw[i].l;
liu[liu_k].r=cw[i].r;
liu[liu_k].id=cw[i].id;
continue;
}
if(belong[cw[i].l]!=belong[L]){
cnt_L=max(cnt_L-5,0);cnt_R+=5;
for(int j=cnt_L;j<=cnt_R;++j)cnt[j]=0;
ans=0;R=cw[i].r;L=belong[cw[i].l]*sz;
cnt_L=INF,cnt_R=0;
for(int j=L;j<=R;++j)update(j,1);
tmp_ans=ans;
}
ans=tmp_ans;L=belong[cw[i].l]*sz;
while(R<cw[i].r)update(++R,1);
tmp_ans=ans;
while(L>cw[i].l)update(--L,1);
Ans[cw[i].id]=ans;
for(int j=L;j<belong[cw[i].l]*sz;++j)update(j,-1);
}
sort(liu+1,liu+liu_k+1,cmp2);
L=0;
for(int i=1;i<=liu_k;++i){
if(liu[i].l!=L){
ans=0;
for(int j=0;j<=k;++j)cnt[j]=0;
L=liu[i].l,R=liu[i].r;
for(int j=L;j<=R;++j)update(j,1);
}else{
for(int j=R+1;j<=liu[i].r;++j){
update(j,1);
}
R=liu[i].r;
}
Ans[liu[i].id]=ans;
}
for(int i=1;i<=m;++i){
printf("%lld\n",Ans[i] );
}
return 0;
}
bzoj4241