SP1557 GSS2 - Can you answer these queries II
XIV.SP1557 GSS2 - Can you answer these queries II
我认为这是GSS题目中难度最大的一道,不接受反驳。
这题中出现多次的只给算一次,应该咋办呢?
我们回忆起这种情况的经典老题:[SDOI2009]HH的项链。正解是将询问离线后按照右端点递增排序,然后出现多次的,就只计算从最后一次出现的位置到当前这个位置这段区间的贡献。
于是本题也可以类似地做。
我们仍然按照右端点递增顺序枚举,设当前右端点为i。我们维护对于每个位置j,子段[j,i]的和,设为sj。则当i从i−1移动到i时,区间[lasai+1,i]中的所有sj都会被增加ai。于是我们可以用线段树维护s数组。
则我们发现,对于一次询问[l,r],我们只需要求出当i=r时,区间[l,r]中的历史最大值即可。
我们考虑对于线段树上每个节点维护这样一些东西:
-
mx,它为区间中当前所有si的最大值。
-
MX,它为区间中历史si的最大值。
-
tag,它为区间的懒标记。
-
TAG,它为从上次
pushdown
以来,tag的最大值。
当我们修改一个位置的值的时候:
-
mx增加这对应的值;
-
tag增加对应的值;
-
MX与当前mx取max;
-
TAG与当前tag取\max;
当我们pushdown
的时候:
-
子节点的MX与mx_{son}+TAG_{fa}取\max;
-
子节点的TAG与tag_{son}+TAG_{fa}取\max;
-
之后,子节点的mx与tag正常地更新。
-
然后,父节点的tag与TAG清空。
我们可以把这俩玩意轻松地二合一:
void ADD(int x,int y,int z=0){z=max(z,y),seg[x].MX=max(seg[x].MX,seg[x].mx+z),seg[x].TAG=max(seg[x].TAG,seg[x].tag+z),seg[x].mx+=y,seg[x].tag+=y;}
询问的时候,就直接返回对应区间的MX即可。
时间复杂度O(n\log n)。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,a[100100],res[100100];
map<int,int>mp;
struct Query{
int l,r,id;
friend bool operator <(const Query &x,const Query &y){
return x.r<y.r;
}
}q[100100];
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
struct SegTree{
ll mx,tag,MX,TAG;//mx:the current maximum in the section; MX:the history maximum in the section; tag:the lazy tag for mx; TAG:the lazy tag for MX
}seg[400100];
void ADD(int x,int y,int z=0){z=max(z,y),seg[x].MX=max(seg[x].MX,seg[x].mx+z),seg[x].TAG=max(seg[x].TAG,seg[x].tag+z),seg[x].mx+=y,seg[x].tag+=y;}
#define pushdown(x) ADD(lson,seg[x].tag,seg[x].TAG),ADD(rson,seg[x].tag,seg[x].TAG),seg[x].tag=seg[x].TAG=0
#define pushup(x) seg[x].mx=max(seg[lson].mx,seg[rson].mx),seg[x].MX=max(seg[lson].MX,seg[rson].MX)
void modify(int x,int l,int r,int L,int R,int val){
if(l>R||r<L)return;
if(L<=l&&r<=R){ADD(x,val);return;}
pushdown(x),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),pushup(x);
}
int query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 0;
if(L<=l&&r<=R)return seg[x].MX;
pushdown(x);
return max(query(lson,l,mid,L,R),query(rson,mid+1,r,L,R));
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+m+1);
for(int i=1,j=1;i<=n;i++){
modify(1,1,n,mp[a[i]]+1,i,a[i]),mp[a[i]]=i;
while(j<=m&&q[j].r<=i)res[q[j].id]=query(1,1,n,q[j].l,q[j].r),j++;
}
for(int i=1;i<=m;i++)printf("%d\n",res[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?