把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

题面传送门
话说我居然连快读都没加就过了。
容易想到莫队。
首先可以看出一个节点增/删有两个贡献:区间比它小的数的个数和区间比它大的数的和。
容易想到可以用树状数组维护,但是这个是\(O(n\sqrt nlogw)\)的,不是很优秀。
考虑莫队二次离线,那么分开算贡献即可。
注意离线时用域值分块可以做到\(O(n\sqrt n)\)
注意这道题还要离散,离散后算贡献别忘了离散回去。
代码实现:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,a[500039],l,r,mid,maxn,nows[500039],tots[500039],ys[500039];
long long fs[339],f[100039],ans[500039],tot[500039],f1[500039],f2[500039],q[500039];
struct yyy{int x,y,id;}s[500039],tmp;
inline bool cmp(yyy x,yyy y){return x.x/k==y.x/k?(((x.x/k)&1)?x.y<y.y:x.y>y.y):x.x<y.x;}
struct ques{int x,y,flag,id;}tmps;
vector<ques> g[500039];
inline void get1(int x){
	register int i;
	for(i=x+1;i<=x/k*k+k-1;i++) f[i]++;
	for(i=x/k+1;i<=maxn/k;i++) fs[i]++;
}
inline void get2(int x){
	register int i;
	for(i=0;i<x/k;i++) fs[i]+=ys[x];
	for(i=x/k*k;i<x;i++) f[i]+=ys[x];
}
inline void ls(int &x){for(l=0,r=n;l+1<r;)mid=l+r>>1,(x>nows[mid])?(l=mid):(r=mid);x=tots[r];}
int main(){
	freopen("1.in","r",stdin);
	register int i,j,h;
	scanf("%d%d",&n,&m);k=sqrt(n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]),q[i]=q[i-1]+a[i],nows[i]=a[i];
	sort(nows+1,nows+n+1);
	for(i=1;i<=n;i++) tots[i]=((i^1)?(tots[i-1]+(nows[i]!=nows[i-1])):1),ys[tots[i]]=nows[i];
	for(i=1;i<=n;i++) ls(a[i]),maxn=max(maxn,a[i]);
	for(i=1;i<=m;i++)scanf("%d%d",&x,&y),s[i]=(yyy){x,y,i};
	sort(s+1,s+m+1,cmp);
	for(i=1;i<=n;i++) get1(a[i]),f1[i]=fs[a[i]/k]+f[a[i]];
	for(memset(f,0,sizeof(f)),memset(fs,0,sizeof(fs)),i=1;i<=n;i++)get2(a[i]),f2[i]=fs[a[i]/k]+f[a[i]];
	for(l=1,r=0,i=1;i<=m;i++){
		tmp=s[i];
		if(r<tmp.y){
			g[l-1].push_back((ques){r+1,tmp.y,-1,i});
			while(r<tmp.y)ans[i]+=f1[++r]*ys[a[r]]+f2[r];
		}
		if(r>tmp.y){
			g[l-1].push_back((ques){tmp.y+1,r,1,i});
			while(r>tmp.y)ans[i]-=f1[r]*ys[a[r]]+f2[r--];
		}
		if(l>tmp.x){
			g[r].push_back((ques){tmp.x,l-1,1,i});
			while(l>tmp.x)ans[i]-=f1[--l]*ys[a[l]]+f2[l];
		}
		if(l<tmp.x){
			g[r].push_back((ques){l,tmp.x-1,-1,i});
			while(l<tmp.x)ans[i]+=f1[l]*ys[a[l]]+f2[l++];
		}
	}
	for(memset(f,0,sizeof(f)),memset(fs,0,sizeof(fs)),i=1;i<=n;i++){
		get1(a[i]);
		for(j=0;j<g[i].size();j++){
			tmps=g[i][j];
			for(h=tmps.x;h<=tmps.y;h++) 
			ans[tmps.id]+=(fs[a[h]/k]+f[a[h]])*ys[a[h]]*tmps.flag;
		}
	}
	for(memset(f,0,sizeof(f)),memset(fs,0,sizeof(fs)),i=1;i<=n;i++){
		get2(a[i]);
		for(j=0;j<g[i].size();j++){
			tmps=g[i][j];
			for(h=tmps.x;h<=tmps.y;h++) ans[tmps.id]+=(fs[a[h]/k]+f[a[h]])*tmps.flag;
		}
	}
	for(i=1;i<=m;i++) ans[i]+=ans[i-1],tot[s[i].id]=ans[i]+q[s[i].y]-q[s[i].x-1];
	for(i=1;i<=m;i++) printf("%lld\n",tot[i]);
}
posted @ 2021-02-04 13:30  275307894a  阅读(74)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end