BZOJ 4241 历史研究
程序员文章站
2022-03-03 14:46:42
...
BZOJ 4214
http://www.lydsy.com/JudgeOnline/problem.php?id=4241
区间询问。
询问元素大小与出现次数乘积的最大值。
借此学习回滚莫队。
经典的莫队:对于区间[L,R] 向别的区间转移状态时。有时是删除。有时是插入。同时需要维护。这类问题需要插入和删除,以及维护比较快的情况下。才可以实现。
回滚莫队:插入和删除是互反的操作。对于有些问题。插入和删除好办。维护困难。回滚莫队可以解决:插入维护时困难,或者,删除维护时困难的问题。(必须有一个容易办到)
这里回滚模队意思应该是保留了某个区间的状态。
更直白的说。插入和删除简单。某个操作的维护不简单。
对于那个操作。我们也不打算维护。而是记录。
我们对序列按m 分块后。形成[km,km+m]
的区间。
我们记询问{Li,Ri∣∣1≤i≤r} 有:Li,Ri,为:li∈[km,km+m],Ri>km+m
我们对区间分开维护:
对于插入简单,且插入维护简单的问题。
每次只维护[km+m+1,Ri]
对于[li,km+m] ,直接暴力插入。求解。然后删除(不维护的删除,将[li,km+m] 产生的影响消去。这就需要我们记录[km+m+1,Ri] 的状态了。)
相反。对于删除简单。可以倒着来。
T(n)=O(nn‾√)
这个题目可以说上面思想的模版题了。
#include <algorithm>
#include <string.h>
#include <stdio.h>
#include <cmath>
#define MAXN 100005
using namespace std;
typedef long long LL;
const char l='0'-1;
const char r='9'+1;
struct Io
{
char A[MAXN],*pb,*pe;
void Io_fread()
{
pe=A+fread(A,1,MAXN,stdin);
pb=A;
}
Io()
{
pe=pb=A;
}
int read()
{
if(pb==pe)
{
Io_fread();
if(pb==pe)return 0;
}
while(*pb==' '||*pb=='\n'||*pb=='\r')
{
pb++;
if(pb==pe)
{
Io_fread();
if(pb==pe)return 0;
}
}
int ans=0;
while(*pb>l&&*pb<r)
{
ans=ans*10+(*pb-'0');
pb++;
if(pb==pe)
{
Io_fread();
if(pb==pe)return ans;
}
}
return ans;
}
}I;
struct node
{
int l,r,L,id;
node(){}
bool operator <(const node &A)const
{
if(L!=A.L)return L<A.L;
return r<A.r;
}
}Q[MAXN];
LL ans[MAXN];
int X[MAXN];
int tmp[MAXN];
LL cnt[MAXN];
int vis[MAXN];
int main ()
{
//freopen("/Users/gaoxusheng/Desktop/In.txt","r",stdin);
int n,q,m;
n=I.read();
q=I.read();
m=sqrt(n+10);
for(int i=0;i<n;i++)
{
tmp[i]=I.read();
X[i+1]=tmp[i];
}
for(int i=0;i<q;i++)
{
Q[i].l=I.read();
Q[i].r=I.read();
Q[i].L=Q[i].l-Q[i].l%m+m;
Q[i].id=i;
}
sort(Q,Q+q);
sort(tmp,tmp+n);
int size=(int)(unique(tmp,tmp+n)-tmp);
for(int i=1;i<=n;i++) X[i]=(int)(lower_bound(tmp,tmp+size,X[i])-tmp);
int v=0,L=-1,R=-1;
LL maxn=0;
for(int i=0;i<q;i++)
{
if(L!=Q[i].L)
{
v++;
maxn=0;
R=Q[i].L-1;
L=Q[i].L;
}
while(R<Q[i].r)
{
R++;
if(vis[X[R]]<v)cnt[X[R]]=0;
vis[X[R]]=v;
cnt[X[R]]+=tmp[X[R]];
if(cnt[X[R]]>maxn)maxn=cnt[X[R]];
}
LL bu=maxn;
int s=min(L,Q[i].r+1);
for(int j=Q[i].l;j<s;j++)
{
if(vis[X[j]]<v)cnt[X[j]]=0;
vis[X[j]]=v;
cnt[X[j]]+=tmp[X[j]];
if(cnt[X[j]]>bu)bu=cnt[X[j]];
}
ans[Q[i].id]=bu;
for(int j=Q[i].l;j<s;j++) cnt[X[j]]-=tmp[X[j]];
}
for(int i=0;i<q;i++) printf("%lld\n",ans[i]);
return 0;
}
上一篇: (超详细)centos7.2离线安装mysql5.7.18.tar.gz
下一篇: Ubuntu 16.04.6 LTS 服务器端运行 Jupyter notebook,本地浏览器访问 Jupyter notebook
推荐阅读
-
BZOJ1008
-
BZOJ1008: [HNOI2008]越狱(快速幂)
-
BZOJ1927: [Sdoi2010]星际竞速(最小费用最大流 最小路径覆盖)
-
BZOJ4650: [Noi2016]优秀的拆分(hash 调和级数)
-
BZOJ4598: [Sdoi2016]模式字符串(点分治 hash)
-
BZOJ1925: [Sdoi2010]地精部落(dp)
-
BZOJ4602: [Sdoi2016]齿轮(并查集 启发式合并)
-
BZOJ5462: [APIO2018] 新家(K-D Tree)
-
BZOJ4513: [Sdoi2016]储能表(数位dp)
-
BZOJ2946 [Poi2000]公共串(后缀自动机)