其他分享
首页 > 其他分享> > P5501 [LnOI2019]来者不拒,去者不追

P5501 [LnOI2019]来者不拒,去者不追

作者:互联网

来者不拒,去者不追

考虑莫队,挪动指针往区间 \([l,r]\) 中加入一个数 \(x\),产生的贡献就是 \(比 x 大的数之和 + 比 x 小的数的个数\times x +x\)
然后这样是 \(O(n\sqrt m \log n\)) 的

发现如果不加最后那个 \(x\) 的话就是可差分的(等于对 \([1,r]\) 的贡献减去对 \([1,l]\) 的贡献),于是考虑二次离线
预处理简单,二次离线的时候会产生 \(O(n)\) 此插入一个数的修改和 \(O(n\sqrt n)\) 此询问上面的那两个信息
在值域上分块做到 \(O(1)\) 查询,\(O(\sqrt n)\) 修改即可

最后输出前把那个 \(x\) 加回来

#define N 500006
#define B 707
#define V 100000
#define VB 316
int n,m;
struct Ask{
	int l,r,id;
};
Ask ask[N];
struct Node{
	int L,R,i,k;
};
std::vector<Node>change[N];
int belong[N];
long long a[N];
long long bsum[VB+6],sum[V+6],bnum[VB+6],num[V+6];
long long fxx[N],ans[N];
inline void pre(){
	for(int i=1;i<=V;i++) belong[i]=(i-1)/VB+1;
	for(int i=1;i<=n;i++){
		fxx[i]=bsum[belong[a[i]]]+sum[a[i]]+a[i]*(bnum[belong[a[i]]]+num[a[i]]);
		for(int j=a[i]-1;belong[j]==belong[a[i]];j--) sum[j]+=a[i];
		for(int j=belong[a[i]]-1;j;j--) bsum[j]+=a[i];
		for(int j=a[i]+1;belong[j]==belong[a[i]];j++) num[j]++;
		for(int j=belong[a[i]]+1;j<=belong[V];j++) bnum[j]++;
	}
	for(int i=1;i<=n;i++) fxx[i]+=fxx[i-1];
	std::memset(bsum,0,sizeof bsum);std::memset(sum,0,sizeof sum);std::memset(bnum,0,sizeof bnum);std::memset(num,0,sizeof num);
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read(),belong[i]=(i-1)/B+1;
	for(int i=1;i<=m;i++) ask[i].l=read(),ask[i].r=read(),ask[i].id=i;
	std::sort(ask+1,ask+1+m,[](const Ask &a,const Ask &b){return belong[a.l]==belong[b.l]?a.r<b.r:a.l<b.l;});
	pre();
	for(int l=1,r=0,L,R,i=1;i<=m;i++){
		L=ask[i].l;R=ask[i].r;
		if(r<R) change[l-1].push_back({r+1,R,i,-1}),ans[ask[i].id]+=fxx[R]-fxx[r],r=R;
//		while(r<ask[i].r) ans[ask[i].id]+=fxx[++r];
		if(l>L) change[r].push_back({ask[i].l,l-1,i,1}),ans[ask[i].id]-=fxx[l-1]-fxx[L-1],l=L;
//		while(l>ask[i].l) ans[ask[i].id]-=fxx[--l];
		if(r>R) change[l-1].push_back({ask[i].r+1,r,i,1}),ans[ask[i].id]-=fxx[r]-fxx[R],r=R;
//		while(r>ask[i].r) ans[ask[i].id]-=fxx[r--];
		if(l<L) change[r].push_back({l,ask[i].l-1,i,-1}),ans[ask[i].id]+=fxx[L-1]-fxx[l-1],l=L;
//		while(l<ask[i].l) ans[ask[i].id]+=fxx[l++];
	}
	for(int i=1;i<=n;i++){
		for(int j=a[i]-1;belong[j]==belong[a[i]];j--) sum[j]+=a[i];
		for(int j=belong[a[i]]-1;j;j--) bsum[j]+=a[i];
		for(int j=a[i]+1;belong[j]==belong[a[i]];j++) num[j]++;
		for(int j=belong[a[i]]+1;j<=belong[V];j++) bnum[j]++;
		for(const Node &x:change[i]){
			register long long tmp=0;
			for(int j=x.L;j<=x.R;j++) tmp+=bsum[belong[a[j]]]+sum[a[j]]+a[j]*(bnum[belong[a[j]]]+num[a[j]]);
			ans[ask[x.i].id]+=x.k*tmp;
		}
	}
	for(int i=1;i<=n;i++) a[i]+=a[i-1];
	for(int i=1;i<=m;i++) ans[ask[i].id]+=ans[ask[i-1].id];
	for(int i=1;i<=m;i++) ans[ask[i].id]+=a[ask[i].r]-a[ask[i].l-1];
	for(int i=1;i<=m;i++) writeEN(ans[i]);
	return RET;
}

标签:fxx,LnOI2019,int,long,P5501,去者,ans,ask,id
来源: https://www.cnblogs.com/suxxsfe/p/15903612.html