ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-06-29 12:35:43  阅读:143  来源: 互联网

标签:tag2 LnOI2019 int 题解 memset -- 去者 c2 include


题面

首先进行一个转化:每个询问区间 \([l,r]\) 中一对 \((i,j)\),如果 \(a_i< a_j\) 会造成 \(a_i\) 的贡献。最后再加一个区间和就是答案。

考虑这是一个区间每对数的贡献,并且具有可减性,上莫队二次离线那一套。考虑一个位置 \(x\) 对一个区间 \([l,r]\) 的贡献 \(f(x,[l,r])\),拆成两部分:

  • \([l,r]\) 中 \(< a_x\) 的数的个数为 \(c\),贡献 \(c\times a_x\)

  • \([l,r]\) 中 \(> a_x\) 的数的和 \(s\)

两部分都是可减信息,由于莫队二次离线是 \(O(n)\) 次单点修改,\(O(n\sqrt m)\) 次单点查询,所以需要平衡一下复杂度,在值域上分块可以做到 \(O(\sqrt V)\) 修改,\(O(1)\) 查询(其中 \(V\) 是值域)。总复杂度 \(O(n\sqrt V+n\sqrt m+m)\)。

点击查看代码
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#define memset __builtin_memset
#define pb push_back
typedef long long ll;
inline void chkmax(int &a,const int &b){if(b>a)a=b;}
const int N=5e5+13,M=5e5+13,B=1000+13,BN=400,BM=350;
int n,m,lim,tot,a[N],fromq[N],from[M],L[B],R[B],c1[M],tag1[B];
ll pre[N],c2[M],tag2[B],f[N];
struct Ques{
	int l,r,id;ll sum;
	inline bool operator <(const Ques &a)const{return fromq[l]!=fromq[a.l]?fromq[l]<fromq[a.l]:(fromq[l]&1?r<a.r:r>a.r);}
}q[N];
struct Node{int l,r,id,op;};
std::vector<Node> b[N];
ll ans[N];
int main(){
#ifdef winterfrost
	freopen("pai.in","r",stdin);
	freopen("P5501.out","w",stdout);
#endif
//	return system("fc code1.out code2.out"),0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]),pre[i]=pre[i-1]+a[i],chkmax(lim,a[i]);
	for(int i=1;i<=lim;++i){
		from[i]=i/BM+1;
		if(from[i]!=from[i-1]) R[tot]=i-1,L[++tot]=i;
	}
	R[tot]=lim;
	for(int i=1;i<=n;++i){
		f[i]=(ll)(c1[a[i]]+tag1[from[a[i]]])*a[i]+c2[a[i]]+tag2[from[a[i]]];
		for(int j=a[i]+1;j<=R[from[a[i]]];++j) ++c1[j];
		for(int j=from[a[i]]+1;j<=tot;++j) ++tag1[j];
		for(int j=a[i]-1;j>=L[from[a[i]]];--j) c2[j]+=a[i];
		for(int j=from[a[i]]-1;j>=1;--j) tag2[j]+=a[i];
	}
	for(int i=1;i<=m;++i) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
	for(int i=1;i<=n;++i) fromq[i]=i/BN+1;
	std::sort(q+1,q+m+1);
	for(int i=1,l=1,r=0;i<=m;++i){
		if(l>q[i].l) b[r].pb((Node){q[i].l,l-1,i,1});
		while(l>q[i].l) --l,q[i].sum-=f[l];
		if(r<q[i].r) b[l-1].pb((Node){r+1,q[i].r,i,-1});
		while(r<q[i].r) ++r,q[i].sum+=f[r];
		if(l<q[i].l) b[r].pb((Node){l,q[i].l-1,i,-1});
		while(l<q[i].l) q[i].sum+=f[l],++l;
		if(r>q[i].r) b[l-1].pb((Node){q[i].r+1,r,i,1});
		while(r>q[i].r) q[i].sum-=f[r],--r;
	}
	memset(c1,0,sizeof c1);memset(c2,0,sizeof c2);memset(tag1,0,sizeof tag1);memset(tag2,0,sizeof tag2);
	for(int i=1;i<=n;++i){
		for(int j=a[i]+1;j<=R[from[a[i]]];++j) ++c1[j];
		for(int j=from[a[i]]+1;j<=tot;++j) ++tag1[j];
		for(int j=a[i]-1;j>=L[from[a[i]]];--j) c2[j]+=a[i];
		for(int j=from[a[i]]-1;j>=1;--j) tag2[j]+=a[i];
		for(auto x:b[i])
			for(int j=x.l;j<=x.r;++j) q[x.id].sum+=x.op*((ll)(c1[a[j]]+tag1[from[a[j]]])*a[j]+c2[a[j]]+tag2[from[a[j]]]);
	}
	for(int i=1;i<=m;++i) ans[q[i].id]=(q[i].sum+=q[i-1].sum)+pre[q[i].r]-pre[q[i].l-1];
	for(int i=1;i<=m;++i) printf("%lld\n",ans[i]);
	return 0;
}

标签:tag2,LnOI2019,int,题解,memset,--,去者,c2,include
来源: https://www.cnblogs.com/winterfrost/p/p5501-solution.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有