P3889 [GDOI2014] 吃
Demeanor_Roy · · 题解
-
原题链接
-
好久没写题解了。(指一周
看到
考虑对
枚举
发现第一个条件特别烦,又因为限制条件之间是或者的关系,考虑直接把条件拆开。换句话说,对所有询问,求出满足第一个条件前半部分与第二个条件的最大的
显然拆出来的两部分对称,这里以满足第一个条件前半部分为例讲解。
不妨将上述条件转化为
于是问题得到解决,时间复杂度为
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
#define mid ((tr[p].l+tr[p].r)>>1)
const int N=1e5+10;
int n,m,c,v[N],ans[N];
vector<int> d[N],pos[N];
vector<pair<int,int>> add[N];
struct Query
{
int l,r,id;
}q[N];
struct node
{
int l,r,mx;
}tr[N<<2];
inline void build(int p,int l,int r)
{
tr[p].l=l;tr[p].r=r;tr[p].mx=0;
if(l==r) return void();
build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}
inline void change(int p,int x,int w)
{
if(tr[p].l==tr[p].r) return tr[p].mx=max(tr[p].mx,w),void();
if(x<=mid) change(p<<1,x,w);else change(p<<1|1,x,w);
tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
}
inline int query(int p,int l,int r)
{
if(tr[p].l>=l&&tr[p].r<=r) return tr[p].mx;
int res=0;
if(l<=mid) res=max(res,query(p<<1,l,r));
if(r>mid) res=max(res,query(p<<1|1,l,r));
return res;
}
inline void solveL()
{
for(int i=1;i<=n;i++) add[i].clear();
for(int i=1;i<=m;i++)
{
if(d[i].size()<2) continue;
for(int j=1;j<(int)d[i].size();j++) add[d[i][0]+1].push_back(mp(d[i][j],i));
}
sort(q+1,q+c+1,[](Query A,Query B){return A.l<B.l;});
build(1,1,n);
for(int i=1,j=0;i<=c;i++)
{
while(j+1<=q[i].l)
{
++j;
for(auto x:add[j]) change(1,x.first,x.second);
}
ans[q[i].id]=max(ans[q[i].id],query(1,q[i].l,q[i].r));
}
}
inline void solveR()
{
for(int i=1;i<=n;i++) add[i].clear();
for(int i=1;i<=m;i++)
{
if(d[i].size()<2) continue;
reverse(d[i].begin(),d[i].end());
for(int j=1;j<(int)d[i].size();j++) add[d[i][0]-1].push_back(mp(d[i][j],i));
}
sort(q+1,q+c+1,[](Query A,Query B){return A.r>B.r;});
build(1,1,n);
for(int i=1,j=n+1;i<=c;i++)
{
while(j-1>=q[i].r)
{
--j;
for(auto x:add[j]) change(1,x.first,x.second);
}
ans[q[i].id]=max(ans[q[i].id],query(1,q[i].l,q[i].r));
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
m=max(m,v[i]);pos[v[i]].push_back(i);
}
for(int i=1;i<=m;i++)
for(int j=i;j<=m;j+=i)
for(auto x:pos[j]) d[i].push_back(x);
for(int i=1;i<=m;i++)
{
sort(d[i].begin(),d[i].end());
d[i].erase(unique(d[i].begin(),d[i].end()),d[i].end());
}
scanf("%d",&c);
for(int i=1;i<=c;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
solveL();solveR();
for(int i=1;i<=c;i++) printf("%d\n",ans[i]);
return 0;
}