首页 > 其他分享 >GSS2—去重最大子段和

GSS2—去重最大子段和

时间:2022-12-30 18:34:04浏览次数:42  
标签:pre log 子段 最大值 离线 GSS2 端点 最大

GSS2

题意:给定序列\(a\),若干次询问,求区间最大去重子段和。

询问次数与序列长度在1e5级别。

分析

超级神题。

在线算法,发现维护去重似乎非常困难,考虑将序列离线下来。有了这个离线的条件,由于没有修改操作,我们就可以考虑对询问顺序开始魔改处理了。

1e5常见的做法无非三种可能:\(O(n\sqrt n),O(n\log n),O(n\log^2 n)\)。我们来一个个考虑:

\(O(n\sqrt n)\):莫队 or 根号分治。莫队的话,由于离线后去重便转化为在某个区域内算上贡献,涉及区间操作,套个数据结构复杂度就变成\(O(n\sqrt n\log n)\)起步,无法承受。而根号分治明显就不行(显然应该不会存在什么高效的分类方式)。

\(O(n\log n),O(n\log^2 n)\):涉及根号和区间操作,明显应该是线段树/树状数组/\(Splay\)。因为\(Splay\)超大常数,并且最大子段和存在一个由线段树维护的分治做法,我们首先来考虑线段树。

然后再来考虑,如果是线段树该怎么做。利用离线操作,一个套路是:

对询问的某端点进行排序,高效维护某个端点单向移动且支持查询以这个移动端点为端点的区间的答案。

加上去重的特殊性,我们考虑将所有的询问按\(r\)排序,并且令最初的\(r\)指针为\(1\),不断向后移动并处理询问。

维护一个答案序列(也许可以理解为贡献序列)\(b\)。
考虑移动指针\(r\)加入一个新的数会怎么样,显然\(a_r\)产生贡献的范围是:\([pre_{r}+1,r]\),其中\(pre_i\)表示值为\(a_i\)的数的上一次出现位置,可以在\(O(n)\)内预处理出。

所以我们将\(b_i,i\in[pre_r+1,r]\)全部加上\(a_r\),这样我们就满足,在任意时刻,\(b_x\)表示\([x,r]\)的去重后和。

再来考虑如何求解最大子段和问题。

首先,因为此时的\(b_i\)已经代表了\([i,r]\)的去重后和,那么我们就可以查个最大值即可统计出右端点为\(r\)的最大子段和。

受这种思想的启发,回溯一个阶段,当\(r'=r-1\)的时候,我们也可以查个最大值得到右端点为\(r-1\)的最大子段和。以此类推,进行若干次操作即可得到答案。

但,显然这个做法有优化的空间,我们明显可以保存\(r-1\)及其之前的最大值,也即维护区间历史最大值,每一次加入操作之后更新一下历史最大值即可。

这样我们就得到了一个做法:

  1. 读入询问,离线,统计\(pre\)
  2. 建立线段树,维护区间最大值,区间历史最大值
  3. 将询问按右端点排序,建立指针\(r\)并不断右移,每次插入就在\([pre_r+1,r]\)上加上\(a_r\)。每次查询就查找\([ask[i].l,ask[i].r](ask[i].r=r)\)的历史最大值。

至此,我们得到了一个\(O(n\log n)\)的优秀算法。

#define N 100050
#define ll long long
int n,m,a[N],pre[N],b[N];
ll ans[N];
struct node{
	int l,r;ll mx,hmx,lz,hlz;
}t[N<<2];
struct Ask{
	int l,r,id;
	bool operator<(const Ask b){
		return r==b.r?l<b.l:r<b.r;
	}
}ask[N];
#define lc x<<1
#define rc x<<1|1
void read(int &x){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	x=s*w;
}
void pushup(int x){
	t[x].mx=max(t[lc].mx,t[rc].mx);
	t[x].hmx=max(t[x].hmx,t[x].mx);
}
void pushdown(node &a,node &b,node &c){
	b.hmx=max(b.hmx,b.mx+a.hlz);
	c.hmx=max(c.hmx,c.mx+a.hlz);
	b.hlz=max(b.hlz,b.lz+a.hlz);
	c.hlz=max(c.hlz,c.lz+a.hlz);
	b.mx+=a.lz;
	c.mx+=a.lz; 
	b.lz+=a.lz;
	c.lz+=a.lz;
	a.lz=a.hlz=0;
}
void pushdown(int x){
	pushdown(t[x],t[lc],t[rc]);
}
void build(int l,int r,int x){
	t[x]={l,r,0,0,0,0};
	if(l==r)return ;
	int mid=l+r>>1;
	build(l,mid,lc);
	build(mid+1,r,rc);
}
ll find(int l,int r,int x){
	if(l<=t[x].l&&t[x].r<=r){
		return t[x].hmx;
	}
	pushdown(x);
	ll ans=0ll;
	int mid=t[x].l+t[x].r>>1;
	if(l<=mid)ans=max(find(l,r,lc),ans);
	if(mid<r)ans=max(find(l,r,rc),ans);
	pushup(x);
	return ans;
}
void change(int l,int r,ll k,int x){
	if(l<=t[x].l&&t[x].r<=r){
		t[x].lz+=k;
		t[x].hlz=max(t[x].hlz,t[x].lz);
		t[x].mx+=k;
		t[x].hmx=max(t[x].hmx,t[x].mx);
		return ;
	}
	pushdown(x);
	int mid=t[x].l+t[x].r>>1;
	if(l<=mid)change(l,r,k,lc);
	if(mid<r)change(l,r,k,rc);
	pushup(x);
}
void init(){
	read(n);
	build(1,n,1);
	for(int i=1;i<=n;i++)read(a[i]);
	for(int i=1;i<=n;i++)pre[i]=b[a[i]],b[a[i]]=i;
	read(m);
	for(int i=1;i<=m;i++)read(ask[i].l),read(ask[i].r),ask[i].id=i;
	sort(ask+1,ask+m+1);
}
void solve(){
	int l=1;
	for(int r=1;r<=n;++r){
		change(pre[r]+1,r,a[r],1);
		while(ask[l].r==r&&l<=m){
			ans[ask[l].id]=find(ask[l].l,ask[l].r,1);
			l++;
		}
	}
}
int main(){
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	init();
	solve();
	for(int i=1;i<=m;i++){
		printf("%lld\n",ans[i]);
	}
}

标签:pre,log,子段,最大值,离线,GSS2,端点,最大
From: https://www.cnblogs.com/oierpyt/p/17015616.html

相关文章

  • 最大公约数_辗转相除法_更相减损术_原理
    辗转相除法算法使用要计算\(a\)与\(b\)的最大公约数,且\(a\÷\b=q\cdotsr\\\(a>=b)\).若\(r\not=0\),可将计算\(a\)与\(b\)的最大公约数,转为计算\(......
  • Ubuntu 修改文件最大打开数
    设置#系统echo'fs.file-max=65535'|sudotee-a/etc/sysctl.confsudosysctl-p#用户sudotee-a/etc/security/limits.conf<<EOF*hard......
  • 深度学习基础课:最大池化层的后向传播推导
    大家好~本课程为“深度学习基础班”的线上课程,带领同学从0开始学习全连接和卷积神经网络,进行数学推导,并且实现可以运行的Demo程序线上课程资料:本节课录像回放加QQ群,获得......
  • P1198 JSOI2008 最大数
    P1198JSOI2008最大数-洛谷|计算机科学教育新生态(luogu.com.cn)采用ST表维护RMQ。对于插入操作,设插入后数列长度变为\(n\),我们只需重新修改满足\(i+2^j-......
  • AcWing246. 区间最大公约数
    题目描述给定一个长度为\(N\)的数列\(A\),以及\(M\)条指令,每条指令可能是以下两种之一:Clrd,表示把\(A[l],A[l+1],…,A[r]\)都加上\(d\)。Qlr,表示询问\(A[l......
  • [答疑精选]乱七八糟图最大的问题
    乱七八糟图最大的问题绍校(207***28)17:45:17绍校(207***28)17:45:31潘老师请教一下向这种乱七八灶图绍校(207***28)17:45:36别人称之为架构图绍校(207***28)17:45:46......
  • UVA193 Graph Coloring - 一般图最大独立集 -
    题目链接:https://www.luogu.com.cn/problem/UVA193题解:注意不是二分图最大独立集和最大匹配没啥关系直接dfs//bySkyRainWind#include<bits/stdc++.h>#definempr......
  • P1853 投资的最大效益
    P1853投资的最大效益题意:初始资金为\(s\),一共有\(n\)年,\(d\)种债卷,给出债卷的投资额和年利息,求\(n\)年后可以获得的最多资金?思路:由于每年之间买债卷是互不影......
  • Java千问06:Java语言中最大的整数再加1等于多少?看完秒懂!
    ​已知Java语言中int类型所能表示的最大整数为2147483647,请问以下代码执行结果是什么?一部分人都会认为这段程序压根就无法通过编译,也有人认为,这段程序能够通过编译,但在运行......
  • P1018 [NOIP2000 提高组] 乘积最大
    题目传送门前言事先声明!博主是不会写高精的屑。因此此题只拿到了开\(LL\)的\(\color{orange}{60}\)分。但这并不妨碍我练\(DP\)。思路辨析很容易想到,以前\(i\)......