题目

点这里

考场思考

大概是标准的莫队吧,离散之后来一个线段树加莫队就可以了。

时间复杂度 \(\mathcal O(n\sqrt n\log n)\) 。

然而被卡常了...只有 \(40pts\) ...

自闭中...

#pragma GCC optimize(2)
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std; #define rep(i,__l,__r) for(signed i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair<int,int>
#define Endl putchar('\n')
// #define FILEOI
#define int long long
// #define int unsigned
#define lc (i<<1)
#define rc (i<<1|1) #ifdef FILEOI
# define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
# undef MAXBUFFERSIZE
# define cg (c=fgetc())
#else
# define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
} const int MAXN=1e5; int a[MAXN+5],sqrtN,ans[MAXN+5];
int has[MAXN+5]; struct query{
int id,l,r;
query(const int I=0,const int L=0,const int R=0):id(I),l(L),r(R){}
bool operator < (const query a)const{
if((l/sqrtN)^(a.l/sqrtN))return (l/sqrtN)<(a.l/sqrtN);
return r<a.r;
}
}q[MAXN+5];
struct node{
int l,r,mid,maxx;
node(const int L=0,const int R=0):l(L),r(R),mid((L+R)>>1),maxx(0){}
}tre[MAXN<<2|2];
inline void buildtre(const int i,const int l,const int r){
tre[i]=node(l,r);
if(l==r)return;
int mid=(l+r)>>1;
buildtre(lc,l,mid);
buildtre(rc,mid+1,r);
}
inline void pushup(const int i){
tre[i].maxx=Max(tre[lc].maxx,tre[rc].maxx);
return;
}
inline void add(const int i,const int p,const int delta){
if(tre[i].l==tre[i].r){
tre[i].maxx+=has[tre[i].l]*delta;
return;
}
if(p<=tre[i].mid)add(lc,p,delta);
else add(rc,p,delta);
pushup(i);
}
inline void delet(const int i,const int p,const int delta){
if(tre[i].l==tre[i].r){
tre[i].maxx-=has[tre[i].l]*delta;
return;
}
if(p<=tre[i].mid)delet(lc,p,delta);
else delet(rc,p,delta);
pushup(i);
} int N,Q,X[MAXN+5],tmp[MAXN+5]; signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
qread(N,Q);
sqrtN=(int)sqrt(N*1.0); rep(i,1,N)tmp[i]=X[i]=qread();
sort(tmp+1,tmp+N+1);
int tN=unique(tmp+1,tmp+N+1)-tmp-1;
int pos;
rep(i,1,N){
pos=lower_bound(tmp+1,tmp+tN+1,X[i])-tmp;
has[pos]=X[i];
X[i]=pos;
} int x,y;
rep(i,1,Q){
qread(x,y);
q[i]=query(i,x,y);
}
sort(q+1,q+Q+1); buildtre(1,1,tN);
int l=1,r=0;
rep(t,1,Q){
while(r<q[t].r)add(1,X[++r],1);
while(r>q[t].r)delet(1,X[r--],1);
while(l<q[t].l)delet(1,X[l++],1);
while(l>q[t].l)add(1,X[--l],1);
ans[q[t].id]=tre[1].maxx;
}
rep(i,1,Q)writc(ans[i],'\n');
return 0;
}

思路分析及标程

其实正解就是莫队,但是加入了一些小优化。

首先思考:如果没有回退操作怎么办?

那很简单,可以不用线段树维护了,这样我们就可以丢掉 \(\log\) 了。

但是怎么才能实现呢?

分析:我们的回退操作是在哪里涉及到的?

其实,对于一般莫队,在左端点都在同一个块里面的时候,我们的右端点都是递增的,这是无疑的。

但是我们的左端点却在进行较小范围的摆动,这让我们十分不爽,并只得加入线段树来进行优化。

如果询问的两个端点在同一个块中,直接暴力计算,时间复杂度 \(\mathcal O(\sqrt N)\) 。

如果不在同一个块中,这时候右端点是不断递增的,因此暴力计算右端点的复杂度为 \(\mathcal O(N)\) 。

但是左端点的位置在块内可是飘忽不定的啊,

简单,每次询问之后把左端点移动到所在块的最右段即可,每次计算左端点的复杂度为 \(\mathcal O(\sqrt N)\) 。

因为有 \(\mathcal O(\sqrt N)\) 个块,因此总的时间复杂度为 \(\mathcal O(N\sqrt N)\) 。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std; #define rep(i,__l,__r) for(signed i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair<int,int>
#define Endl putchar('\n')
// #define FILEOI
#define int long long
// #define int unsigned
// #define lc (i<<1)
// #define rc (i<<1|1) #ifdef FILEOI
# define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
# undef MAXBUFFERSIZE
# define cg (c=fgetc())
#else
# define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
} const int MAXN=1e5; int ans[MAXN+5],maxx,alblock;
int N,Q,X[MAXN+5],has[MAXN+5],tN,block[MAXN+5],sqN,cnt[MAXN+5]; struct Query{
int l,r,id;
inline Query(const int L=0,const int R=0,const int I=0):l(L),r(R),id(I){}
inline bool operator <(const Query rhs)const{
if(block[l]==block[rhs.l])return r<rhs.r;
return block[l]<block[rhs.l];
}
}q[MAXN+5]; inline void init(){
qread(N,Q);sqN=(int)sqrt(N*1.0);
rep(i,1,N){
X[i]=has[i]=qread();
block[i]=(i+sqN-1)/sqN;
alblock=Max(alblock,block[i]);
}
sort(has+1,has+N+1);
tN=unique(has+1,has+N+1)-has-1;
rep(i,1,N)X[i]=lower_bound(has+1,has+tN+1,X[i])-has;
} inline void getQuery(){
int l,r;
rep(i,1,Q){
qread(l,r);
q[i]=Query(l,r,i);
}
sort(q+1,q+Q+1);
} inline int solve(const int l,const int r){
static int tmp[MAXN+5];int tmax=0;
rep(i,l,r)tmp[X[i]]=0;
rep(i,l,r)++tmp[X[i]],tmax=Max(tmax,tmp[X[i]]*has[X[i]]);
return tmax;
} inline void add(const int i){
++cnt[X[i]];
maxx=Max(cnt[X[i]]*has[X[i]],maxx);
} inline void delet(const int i){
--cnt[X[i]];
} inline int Get(int i,const int bid){
int Br=bid*sqN,l=Br+1,r=l-1,cur;maxx=0;
memset(cnt,0,sizeof cnt);
for(;block[q[i].l]==bid;++i){
if(block[q[i].l]==block[q[i].r]){
ans[q[i].id]=solve(q[i].l,q[i].r);
continue;
}
while(r<q[i].r)add(++r);
cur=maxx;
while(l>q[i].l)add(--l);
ans[q[i].id]=maxx;
while(l<Br+1)delet(l++);
maxx=cur;
}
return i;
} signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
init();
getQuery(); for(int i=1,id=1;id<=alblock;++id)
i=Get(i,id); rep(i,1,Q)writc(ans[i],'\n');
return 0;
}

「题解」「JOISC 2014 Day1」历史研究的更多相关文章

  1. 「JOISC 2014 Day1」巴士走读

    「JOISC 2014 Day1」巴士走读 将询问离线下来. 从终点出发到起点. 由于在每个点(除了终点)的时间被过来的边固定,因此如果一个点不被新的边更新,是不会发生变化的. 因此可以按照时间顺序, ...

  2. 「JOISC 2014 Day1」 历史研究

    「JOISC 2014 Day1」 历史研究 Solution 子任务2 暴力,用\(cnt\)记录每种权值出现次数. 子任务3 这不是一个尺取吗... 然后用multiset维护当前的区间,动态加, ...

  3. 「JOISC 2014 Day1」历史研究 --- 回滚莫队

    题目又臭又长,但其实题意很简单. 给出一个长度为\(N\)的序列与\(Q\)个询问,每个询问都对应原序列中的一个区间.对于每个查询的区间,设数\(X_{i}\)在此区间出现的次数为\(Sum_{X_{ ...

  4. 【LOJ】#3032. 「JOISC 2019 Day1」馕

    LOJ#3032. 「JOISC 2019 Day1」馕 处理出每个人把馕切成N段,每一段快乐度相同,我们选择第一个排在最前的人分给他的第一段,然后再在未选取的的人中选一个第二个排在最前的切一下,并把 ...

  5. 【LOJ】#3031. 「JOISC 2019 Day1」聚会

    LOJ#3031. 「JOISC 2019 Day1」聚会 听说随机可过? 我想了很久想了一个不会被卡的做法,建出前\(u - 1\)个点的虚树,然后找第\(u\)个点的插入位置,就是每次找一条最长链 ...

  6. 【LOJ】#3030. 「JOISC 2019 Day1」考试

    LOJ#3030. 「JOISC 2019 Day1」考试 看起来求一个奇怪图形(两条和坐标轴平行的线被切掉了一个角)内包括的点个数 too naive! 首先熟练的转化求不被这个图形包含的个数 -- ...

  7. 「JOISC 2022 Day1」京都观光 题解

    Solution 考虑从\((x_1,y_1)\)走到\((x_2,y_2)\)满足只改变一次方向,则容易求出先向南走当且仅当 \[\frac{a_{x_1} - a_{x_2}}{x_1 - x_2 ...

  8. LOJ#2882. 「JOISC 2014 Day4」两个人的星座(计算几何)

    题面 传送门 题解 我们发现如果两个三角形相离,那么这两个三角形一定存在两条公切线 那么我们可以\(O(n^2)\)枚举其中一条公切线,然后可以暴力\(O(n^3)\)计算 怎么优化呢?我们可以枚举一 ...

  9. bzoj4244 & loj2878. 「JOISC 2014 Day2」邮戳拉力赛 括号序列+背包

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4244 https://loj.ac/problem/2878 题解 挺妙的一道题. 一开始一直 ...

随机推荐

  1. xpath解析html标签

    最近忙一个需求:把一个字符串形式的html文档转化成excel. 分解需求: ① 实现语言 ———— python ② html解析 ———— 用 lxml库的etree工具,xpath方式解析文档树 ...

  2. python 中if和elif的区别

    如果程序中判断事件很多,全部用if的话,会遍历整个程序,用elif 程序运行时,只要if或后续某一个elif之一满足逻辑值为True,则程序执行完对应输出语句后自动结束该轮if-elif(即不会再去冗 ...

  3. selenium的定位方法-单元素定位

    selenium自动化测试中,提供了单个元素定位方法,多个元素定位方法,2种方式都是根据元素属性:ID.NAME.CLASS_NAME.TAG_NAME.CSS_SELECTOR.XPATH.LINK ...

  4. 关于微信小程序的分包

    最近开始一份新的工作,接手一个正在开发的小程序,第一步添加客服系统,我们用的网易七鱼,利用微信小程序SDK接入的方式,一顿操作之后,欧欧~~!!~~~,提示没法预览, 究其原因,资源包过大,微信小程序 ...

  5. Linux服务器时间设置及同步

    闲余:夏日将到,园区计划五一期间进行大面积的电网停电检修,运维同学因此将公司测试服务器提前关闭了.收假后,测试告诉我,他发现一个bug--一段定时任务程序未执行,我的第一反应就是--会不会是假期测试服 ...

  6. Iframe 高度自适应,js控制Iframe 高度自适应

     Iframe 高度自适应, js控制Iframe 高度自适应, iframe自适应高度 ================================ ©Copyright 蕃薯耀 2019年12 ...

  7. Winform遍历窗口的所有控件(几种方式实现)

    本文链接:https://blog.csdn.net/u014453443/article/details/85088733 扣扣技术交流群:460189483 C#遍历窗体所有控件或某类型所有控件 ...

  8. Linux常用命令英文全称与中文解释 (pwd、su、df、du等)

    https://blog.csdn.net/qq_40334837/article/details/83819735 Linux常用命令英文全称与中文解释 apt: Advanced Packagin ...

  9. Django组件总结

    Django组件介绍 分页器的使用 分页器在页面中非常常见,当数据库条数数据过多时,页面一次性显示不好看时,我们可以使用分页器,将数据分几次显示. 1.1 数据库内插入大量数据 Booklist=[] ...

  10. it兼职以及行业门户网

    程序员接私活的七大平台 https://www.jianshu.com/p/61a3fabe75fc 1.程序员客栈:程序员的经纪人 https://www.proginn.com/     2.快码 ...