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

题目链接

题目描述

给定长度为 \(n\) 的序列 \(a\),给出 \(m\) 个询问。

对于每个询问,给出一个区间 \([l,r]\),求

\[\sum_{i=l}^{r}{\left(1+\sum_{j=l}^{r}{[a_j<a_i]}\right)a_i} \]

数据范围:\(1\le n,m\le 5\times 10^5\)\(a_i\le 10^5\)\(1\le l \le r \le n\)

时间范围:\(3000\operatorname{ms}\)

Solution 1

看题目可以发现是求区间排名,求区间和显然不好在线维护,考虑莫队。

对于已有的区间 \([l,r]\),若向右插入一个元素,贡献为

\[\sum_{i=l}^{r}{[a_i>a_{r+1}]a_i}+a_{r+1}\left(1+\sum_{i=l}^{r}{[a_i<a_{r+1}]}\right) \]

直接维护的复杂度为 \(\Theta(n\sqrt n\log a_{\max})\),期望得分 \(10\operatorname{pts}\)

Solution 2

上边的带 \(\log\) 莫队是没有前途的,考虑二次离线。

考虑前缀和,向右插入一个元素,贡献为

\[\sum_{i=1}^{r}{[a_i>a_{r+1}]a_i}+a_{r+1}\left(1+\sum_{i=1}^{r}{[a_i<a_{r+1}]}\right)-\sum_{i=1}^{l-1}{[a_i>a_{r+1}]a_i}-a_{r+1}\left(\sum_{i=1}^{l-1}{[a_i<a_{r+1}]}\right) \]

定义 \(f_{r}=\sum_{i=1}^{r-1}{[a_i>a_{r}]a_i}+a_{r}\left(1+\sum_{i=1}^{r-1}{[a_i<a_{r}]}\right)\),则贡献变为

\[f_{r+1}-\sum_{i=1}^{l-1}{[a_i>a_{r+1}]a_i}-a_{r+1}\left(\sum_{i=1}^{l-1}{[a_i<a_{r+1}]}\right) \]

\(f\) 数组预处理出来前缀和,后边的贡献离线下来维护,套上值域分块即可处理。

向左插入同理。

由于 \(n,m\) 同阶,时间复杂度为 \(\Theta(n\sqrt n+n\sqrt{a_\max})\),期望得分 \(100\operatorname{pts}\)

Code

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=500010;
typedef long long LL;
int K[maxn],L[maxn],R[maxn],T;
template<class T>inline void read(T &x){
	x=0;char c;
	do c=getchar();while(c<'0'||c>'9');
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
template<class T>inline void write(T x){
	static char stk[22];int top=0;
	while(x)stk[++top]=x-x/10*10+48,x/=10;
	while(top)putchar(stk[top--]);
	putchar('\n');
}
struct query{
	int l,r,id;
	inline bool operator<(const query &qu)const{
		return K[l]!=K[qu.l]?l<qu.l:((K[l]&1)?r<qu.r:r>qu.r);
	}
}q[maxn];
struct Range{
	int l,r,id,d;
	inline Range(int _l=0,int _r=0,int _id=0,int _d=0){
		l=_l;r=_r;id=_id;d=_d;
	}
};
vector<Range> range[maxn];
struct TreeArray{
	#define lowbit(x) (x&-x)
	LL tr[maxn];
	inline void add(int x,int d){while(x<=100000)tr[x]+=d,x+=lowbit(x);}
	inline LL ask(int x){LL ans=0;while(x)ans+=tr[x],x-=lowbit(x);return ans;}
	inline void clear(){memset(tr,0,sizeof(tr));}
	#undef lowbit
}BIT;
LL f[maxn],pre[maxn];
struct BlockOfRange{
	int bl[maxn],br[maxn],bk[maxn],kt;
	LL v[maxn],tag[maxn],sum;
	inline void Init(){
		kt=sqrt(100010);
		for(int i=1;i<=kt;++i)bl[i]=br[i-1]+1,br[i]=br[i-1]+kt;
		if(R[kt]<100010)bl[kt+1]=br[kt]+1,br[++kt]=100010;
		for(int i=1;i<=kt;++i)for(int j=bl[i];j<=br[i];++j)bk[j]=i;
	}
	inline void add(int x,int d){
		int k=bk[x];sum+=d;
		for(int i=x;i<=br[k];++i)v[i]+=d;
		for(int i=k+1;i<=kt;++i)tag[i]+=d;
	}
	inline LL ask(int x){return tag[bk[x]]+v[x];}
	inline void clear(){
		memset(v,0,sizeof(v));
		memset(tag,0,sizeof(tag));
		sum=0;
	}
}BOR1,BOR2;
LL ans[maxn],res[maxn];
int n,m,a[maxn];
int main(){
	BOR1.Init();BOR2.Init();
	read(n);read(m);
	T=sqrt(n);
	for(int i=1;i<=T;++i)L[i]=R[i-1]+1,R[i]=R[i-1]+T;
	if(R[T]<n)L[T+1]=R[T]+1,R[T]=n;
	for(int i=1;i<=T;++i)for(int j=L[i];j<=R[i];++j)K[j]=i;
	for(int i=1;i<=n;++i)read(a[i]);
	for(int i=1;i<=m;++i){read(q[i].l),read(q[i].r);q[i].id=i;}
	sort(q+1,q+m+1);
	for(int i=1;i<=n;++i){
		f[i]=BIT.ask(a[i]);
		BIT.add(1,a[i]);BIT.add(a[i],-a[i]);
	}
	BIT.clear();
	for(int i=1;i<=n;++i){
		f[i]+=(BIT.ask(a[i]-1)+1)*a[i];
		BIT.add(a[i],1);
	}
	for(int i=1;i<=n;++i)pre[i]=pre[i-1]+f[i];
	int curl=1,curr=0;
	for(int i=1;i<=m;++i){
		int l=q[i].l,r=q[i].r;
		if(curr<r)range[curl-1].push_back(Range(curr+1,r,i,-1)),ans[i]+=pre[r]-pre[curr];
		if(curr>r)range[curl-1].push_back(Range(r+1,curr,i,1)),ans[i]-=pre[curr]-pre[r];
		curr=r;curl=l;
	}
	for(int i=1;i<=n;++i){
		BOR1.add(a[i],a[i]);BOR2.add(a[i],1);
		for(auto qry:range[i]){
			int l=qry.l,r=qry.r,id=qry.id,d=qry.d;
			for(int j=l;j<=r;++j)ans[id]+=(BOR1.sum-BOR1.ask(a[j])+a[j]*BOR2.ask(a[j]-1))*d;
		}
	}
	for(int i=1;i<=n;++i)range[i].clear();BOR1.clear();BOR2.clear();BIT.clear();
	for(int i=n;i;--i){
		f[i]=BIT.ask(a[i]);
		BIT.add(1,a[i]);BIT.add(a[i],-a[i]);
	}
	BIT.clear();
	for(int i=n;i;--i){
		f[i]+=(BIT.ask(a[i]-1)+1)*a[i];
		BIT.add(a[i],1);
	}
	for(int i=n;i;--i)pre[i]=pre[i+1]+f[i];
	curl=1;
	for(int i=1;i<=m;++i){
		int l=q[i].l,r=q[i].r;
		if(curl<l)range[r+1].push_back(Range(curl,l-1,i,1)),ans[i]-=pre[curl]-pre[l];
		if(curl>l)range[r+1].push_back(Range(l,curl-1,i,-1)),ans[i]+=pre[l]-pre[curl];
		curl=l;
	}
	for(int i=n;i;--i){
		BOR1.add(a[i],a[i]);BOR2.add(a[i],1);
		for(auto qry:range[i]){
			int l=qry.l,r=qry.r,id=qry.id,d=qry.d;
			for(int j=l;j<=r;++j)ans[id]+=(BOR1.sum-BOR1.ask(a[j])+a[j]*BOR2.ask(a[j]-1))*d;
		}
	}
	for(int i=2;i<=m;++i)ans[i]+=ans[i-1];
	for(int i=1;i<=m;++i)res[q[i].id]=ans[i];
	for(int i=1;i<=m;++i)write(res[i]);
	return 0;
}
posted @ 2021-05-13 20:00  7103  阅读(181)  评论(0)    收藏  举报