题面
分析
拿到这题后,你会发现这题对于询问要求强制在线,但是询问的对象是不发生改变的,所以我们可以从这个长度为 N N N的序列着手。
通过分析输出内容可以发现,数字越大原始答案越大,所以可以将 n u m num num 数组排序后 O ( n ) O(n) O(n) 地跑出所有 x x x 对应的原始答案,也就得到了每个 x x x 对应的真实答案(真实答案不是整型,所以在比较真实答案大小的时候最好使用乘法而不是除法!!!)。
对于所有 n u m i ≤ x num_i\leq x numi≤x,我们可以先把 [ i , i ] [i,i] [i,i] 当成单独的一个区间来统计答案信息,然后再左右判断是否可以合并,合并时对答案信息的维护是显然的。
本题给的询问限制是区间个数,所以我们自然而然想到了在每个区间个数中找到最大的真实答案对应的信息,然后就是RMQ问题了,使用st表解决。
注意平方的时候会爆int,所以得开long long,而st表开long long有可能会爆,所以可以保存所有 x x x对应的答案信息然后再跑,具体实现可看代码。
代码
#include<bits/stdc++.h>
using namespace std;
/*
需要先把所有x的答案保存下来,然后查询的时候跑st表即可
t1:长度平方和
t2:区间数量
*/
const int N=1e6+5;
int n,q,a,b,x,y,pos[N][23],t2,lg[N],f[N],sz[N],mx;
long long t1,ans,sum[N];
bool ins[N];
struct node{
int x,id;
}num[N];
bool cmp(node a,node b){
return a.x<b.x;
}
int fd(int x){
return x==f[x]?x:f[x]=fd(f[x]);
}
bool check(int x,int y,int k){
if(pos[x][k]==0) return 0;
if(pos[y][k]==0) return 1;
return 1ll*sum[pos[x][k]]*pos[y][k]>1ll*sum[pos[y][k]]*pos[x][k];
}
int main(){
// freopen(".in","r",stdin);
// freopen("tx.out","w",stdout);
// freopen("tx.in","r",stdin);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&num[i].x);
num[i].id=i;
mx=max(mx,num[i].x);
}
sort(num+1,num+1+n,cmp);
int now=1;
for(int i=1;i<=mx;i++){
while(now<=n&&num[now].x<=i){
int x=num[now].id;
t1++,t2++;ins[x]=1;f[x]=x;sz[x]=1;
if(ins[x-1]){
int v=fd(x-1);
t1-=1ll*sz[v]*sz[v]+1ll*sz[x]*sz[x];
sz[v]+=sz[x];
t1+=1ll*sz[v]*sz[v];
f[x]=v;
t2--;
}
if(ins[x+1]){
int v=fd(x+1);
x=fd(x);
t1-=1ll*sz[v]*sz[v]+1ll*sz[x]*sz[x];
sz[v]+=sz[x];
t1+=1ll*sz[v]*sz[v];
f[x]=v;
t2--;
}
now++;
}
sum[i]=t1;
if(sum[pos[t2][0]]*i<=t1*pos[t2][0]){
pos[t2][0]=i;
}
}
for(int i=1;i<=22;i++){
for(int j=1;j+(1<<(i-1))<=n;j++){
if(check(j,j+(1<<(i-1)),i-1)){
pos[j][i]=pos[j][i-1];
}
else{
pos[j][i]=pos[j+(1<<(i-1))][i-1];
}
}
}
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=q;i++){
scanf("%d%d%d%d",&a,&b,&x,&y);
a%=n,b%=n,x%=n,y%=n;
int l=(1ll*a*ans%n+x+n-1)%n+1;
int r=(1ll*b*ans%n+y+n-1)%n+1;
if(l>r) swap(l,r);
int k=lg[r-l+1];
long long tmp,x;
if(check(l,r-(1<<k)+1,k)){
tmp=sum[pos[l][k]];
x=pos[l][k];
}
else{
tmp=sum[pos[r-(1<<k)+1][k]];
x=pos[r-(1<<k)+1][k];
}
if(tmp==0){
printf("-1 -1\n");
printf("%d %d %lld\n",l,r,ans);
ans=1;
}
else{
printf("%lld %lld\n",tmp,x);
printf("%d %d %lld\n",l,r,ans);
ans=1ll*tmp%n*x%n;
}
}
return 0;
}