[Aboi Round 2] 礎の花冠 题解
10pts
直接暴力枚举。
20pts
把询问离线下来,然后做扫描线。
我们发现,对于一个
剩余部分分
这里借用出题人题解的说法:
正解
我们发现
我们考虑沿用 20pts 的思路,对询问离线下来然后做扫描线,假设现在扫到了
1. a_x \le a_r
这类我们直接对
假设询问复杂度为
具体写法就是我们对于值域进行分块,每个块内和整块之间都建立 ST 表,这样子更新一个位置就是要重建单块内的 ST 表和整块之间的 ST 表,我们只对涉及到修改位置的部分进行重建,总复杂度为
2. a_x > a_r
我们也分两种情况讨论。
一、a_r>\sqrt n
我们枚举
二、a_r\le\sqrt n
令
所以对于
答案统计
上文我们只说统计进答案,但是我们没有说怎么统计。其实非常简单,我们维护一个值域分块,同时我们需要记录每个分数的最晚
综上,每部分的复杂度均为
整除分块需要卡常,记得做一下,其思路就是如果说整除分块得到的那个
实现代码
#include <bits/stdc++.h>
using namespace std;
namespace MySpace{
#define lowbit(x) (x&(-x))
#define sqrt sqrtl
#ifdef ONLINE_JUDGE
#define getchar getchar_unlocked
#endif
#define whileu(p) while (p--)
#define forl(a,b,c) for (auto a=b;a<=c;a=a+1)
#define chk(x,y) x=x<y?y:x
#define max(x,y) (x<y?y:x)
inline void read() {}
template <typename T, typename... R>
inline void read(T &x,R &... oth){
x=0;T f=1;
char c=getchar();
while(c<'0' || c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c&15),c=getchar();
x*=f;
read(oth...);
return;
}
template<typename T>
T qpow(T a,T n,T p){
T res=1;
while (n){
if (n&1) res=1ll*res*a%p;
a=1ll*a*a%p;
n>>=1;
}
return res;
}
template<typename T>
T gcd(T a,T b){return (b>0?gcd(b,a%b):a);}
template<typename T>
T exgcd(T a,T b,T& x,T& y){
if (b<=0ll){
x=1ll,y=0ll;
return a;
}
T t=x;
T d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
template<typename T>
T inv(T a,T p){
if (a==1) return 1ll;
T x,y;
if (exgcd(a,p,x,y)!=1ll) return -1ll;
else return (x+p)%p;
}
}
using namespace MySpace;
const int N=400005,V=400000,B=600,blk=800,G=N/blk+5;
int n,m,tot,L[G],R[G];
int a[N],bl[N],ans[N],lt[N],pr[N];
vector<pair<int,int> > q[N];
struct blk1{
int S[G],c[N];
inline void add(int x,int v){
if(x) S[bl[x]]+=v,c[x]+=v;
}
inline int ask(int x){
int res=0;
for(int i=x;i<=R[bl[x]];++i) res+=c[i];
for(int i=bl[x]+1;i<=tot;++i) res+=S[i];
return res;
}
}T;
struct blk2{
int M[G],P[N],S[N],g[N];
inline int ask(int l,int r){
r=min(r,V);
if(r-l+1<=blk){
int res=0;
for(int i=l;i<=r;++i) chk(res,g[i]);
return res;
}
int res=max(S[l],P[r]);
for(int i=bl[l]+1;i<bl[r];++i) chk(res,M[i]);
return res;
}
inline void mod(int x,int v){
g[x]=v,M[bl[x]]=v;
for(int i=x;i<=R[bl[x]];++i) P[i]=v;
for(int i=L[bl[x]];i<=x;++i) S[i]=v;
}
}F;
inline void C(int x,int y){
if(lt[x]<y) T.add(lt[x],-1),T.add(lt[x]=y,1);
}
signed main(){
read(n,m);
tot=(V-1)/blk+1;
bl[0]=1;
for(int i=1;i<=V;++i) bl[i]=(i-1)/blk+1;
for(int i=1;i<=tot;++i){
L[i]=R[i-1]+1;
R[i]=i*blk;
}
L[1]=0;
R[tot]=V;
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<=m;++i){
int l,r;
read(l);
read(r);
q[r].push_back({l,i});
}
for(int i=1;i<=n;++i){
const int v=a[i],sq=sqrt(v);
F.mod(v,i);
C(0,F.ask(v+1,V));
if(a[i]>1000){
for(int l=1,r,P=0;l<=v;C(P,F.ask(l,r)),l=r+1){
if(l>sq) --P,r=v/P;
else P=v/l,r=l;
}
}else{
for(int l=1,r,P=0;l<=v;C(P,F.ask(l,r)),l=r+1){
P=v/l,r=v/P;
}
}
if(v>=B){
for(int j=0,P=0,pos;j<=V;++P,j+=v){
pos=F.ask(j,j+v-1);
C(P,pos);
}
}else{
for(int j=pr[v]+1;j<=i;++j){
C(a[j]/v,j);
}
}
pr[a[i]]=i;
for(unsigned int j=0;j<q[i].size();++j){
ans[q[i][j].second]=T.ask(q[i][j].first);
}
}
for(int i=1;i<=m;++i){
printf("%d\n",ans[i]);
}
return 0;
}