题解:P4587 [FJOI2016] 神秘数
贡献一篇别样的的莫队题解。
考虑新加入一个数对序列神秘数的影响。如果存在一个数
这启示我们一个贪心的思路:维护一个数
如果
如果
此时可以用莫队维护答案了,普通莫队即可。首先进行离散化,值域
设 multiset 的回滚莫队要快。
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define F first
#define S second
using namespace std;
const int N=1e5+5;
int n,m,a[N],B,ans[N],ar[N],b[N],vn,cnt[N],sum[N],pos[N],lp[N],rp[N];
struct qry{
int l,r,x;
}q[N];
bool cmp(qry a,qry b){
if(a.l/B!=b.l/B) return a.l<b.l;
return a.r<b.r;
}
void add(int p){
int x=ar[p];
cnt[x]++;
sum[pos[x]]+=b[x];
}
void del(int p){
int x=ar[p];
cnt[x]--;
sum[pos[x]]-=b[x];
}
int qsum(int k){
int p=upper_bound(b+1,b+vn+1,k)-b-1,res=0;
if(p<=0) return 0;
if(pos[1]==pos[p]) for(int i=1;i<=p;i++) res+=cnt[i]*b[i];
else{
for(int i=1;i<=rp[pos[1]];i++) res+=cnt[i]*b[i];
for(int i=pos[1]+1;i<=pos[p]-1;i++) res+=sum[i];
for(int i=lp[pos[p]];i<=p;i++) res+=cnt[i]*b[i];
}
return res;
}
int getans(){
int cur=0;
while(1){
int s=qsum(cur+1);
if(s==cur) return cur+1;
cur=s;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
vn=unique(b+1,b+n+1)-b-1;
int vB=sqrt(vn)+1;
int vbn=(vn+vB-1)/vB;
for(int i=1;i<=vn;i++) pos[i]=(i-1)/vB+1;
for(int i=1;i<=vbn;i++){
lp[i]=(i-1)*vB+1;
rp[i]=min(i*vB,vn);
}
for(int i=1;i<=n;i++) ar[i]=lower_bound(b+1,b+vn+1,a[i])-b;
B=sqrt(n)+1;
cin>>m;
for(int i=1;i<=m;i++){
cin>>q[i].l>>q[i].r;
q[i].x=i;
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++){
while(l>q[i].l) add(--l);
while(r<q[i].r) add(++r);
while(l<q[i].l) del(l++);
while(r>q[i].r) del(r--);
ans[q[i].x]=getans();
}
for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
return 0;
}