线段树乱做GSS
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树乱做GSS相关的知识,希望对你有一定的参考价值。
线段树乱做GSS
SP1043 GSS1
区间最大子段和,显然可以线段树维护4个变量,左端点开始的答案,右端点结尾的答案,整个区间的答案,整个区间的和。
答案参考题解区
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#define SIZE 50010
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
using namespace std;
int n,m,x,y;
struct SegmentTree{
int sum,lmax,rmax,dat;
}tr[SIZE<<2];
inline int rin(){
int f=1,x=0; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
return f*x;
}
inline void Update(int p){
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
tr[p].lmax=max(tr[p<<1].lmax,tr[p<<1].sum+tr[p<<1|1].lmax);
tr[p].rmax=max(tr[p<<1|1].rmax,tr[p<<1|1].sum+tr[p<<1].rmax);
tr[p].dat=max(max(tr[p<<1].dat,tr[p<<1|1].dat),tr[p<<1].rmax+tr[p<<1|1].lmax);
}
inline void Build(int p,int l,int r){
if(l==r){tr[p].dat=tr[p].sum=tr[p].lmax=tr[p].rmax=rin(); return;}
int mid=(l+r)>>1;
Build(lson); Build(rson);
Update(p);
}
inline SegmentTree Query(int p,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r) return tr[p];
int mid=(l+r)>>1;
if(ql>mid) return Query(rson,ql,qr);
if(qr<=mid) return Query(lson,ql,qr);
else{
SegmentTree ans,a,b;
a=Query(lson,ql,qr); b=Query(rson,ql,qr);
ans.sum=a.sum+b.sum;
ans.dat=max(a.dat,a.rmax+b.lmax),ans.dat=max(ans.dat,b.dat);
ans.lmax=max(a.lmax,a.sum+b.lmax);
ans.rmax=max(b.rmax,b.sum+a.rmax);
return ans;
}
}
int main(){
n=rin();
Build(1,1,n);
m=rin();
for(int i=1;i<=m;i++){
x=rin(),y=rin();
printf("%d\\n",Query(1,1,n,x,y).dat);
}
return 0;
}
SP1557 GSS2
区间最大子段去重和。
考虑离线,预处理每个数上一次出现的位置 p r e [ a i ] pre[a_i] pre[ai]。
将询问按右端点排序。
线段树每个结点维护 4 4 4个变量: s u m , h i s s u m , t a g , h i s t a g sum,hissum,tag,histag sum,hissum,tag,histag。
当前子段和、历史最大子段和、区间加标记,历史最大区间加标记。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
inline LL read(){
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=100005;
struct Node{
LL sum,hix,stag,htag;
Node(){
sum=hix=stag=htag=0;
}
friend Node operator + (Node lf,Node rt){
Node res;
res.sum=max(lf.sum,rt.sum);
res.hix=max(lf.hix,rt.hix);
return res;
}
}b[MAXN*4];
struct Qst{
int l,r,id;
}q[MAXN];
bool cmp(Qst x,Qst y){
return x.r<y.r;
}
int n,m,cur[MAXN*2],pre[MAXN],ql,qr;LL a[MAXN],ans[MAXN],k;
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void pushup(int o){
b[o]=b[lc]+b[rc];
}
void pushdown(int o){//注意更新先后顺序
b[lc].hix=max(b[lc].hix,b[lc].sum+b[o].htag);
b[rc].hix=max(b[rc].hix,b[rc].sum+b[o].htag);
b[lc].sum+=b[o].stag;
b[rc].sum+=b[o].stag;
b[lc].htag=max(b[lc].htag,b[lc].stag+b[o].htag);
b[rc].htag=max(b[rc].htag,b[rc].stag+b[o].htag);
b[lc].stag+=b[o].stag;
b[rc].stag+=b[o].stag;
b[o].stag=b[o].htag=0;
}
void upd(int o,int l,int r){
if(ql<=l&&r<=qr){
b[o].sum+=k;
b[o].hix=max(b[o].hix,b[o].sum);
b[o].stag+=k;
b[o].htag=max(b[o].htag,b[o].stag);
return;
}
pushdown(o);
if(mid>=ql) upd(lc,l,mid);
if(mid<qr) upd(rc,mid+1,r);
pushup(o);
}
Node query(int o,int l,int r){
if(ql<=l&&r<=qr) return b[o];
pushdown(o);
if(mid<ql) return query(rc,mid+1,r);
else if(mid>=qr) return query(lc,l,mid);
else return query(lc,l,mid)+query(rc,mid+1,r);
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
pre[i]=cur[a[i]+(int)1e5];
cur[a[i]+(int)1e5]=i;
}
m=read();
for(int i=1;i<=m;i++){
q[i].l=read(),q[i].r=read();
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int j=1;
for(int i=1;i<=n;i++){
ql=pre[i]+1,qr=i,k=a[i];
upd(1,1,n);
for(;j<=m&&q[j].r<=i;j++){
ql=q[j].l,qr=q[j].r;
ans[q[j].id]=query(1,1,n).hix;
}
}
for(int i=1;i<=m;i++)
printf("%lld\\n",ans[i]);
return 0;
}
逃了,wtcl
以上是关于线段树乱做GSS的主要内容,如果未能解决你的问题,请参考以下文章
SPOJ GSS3 Can you answer these queries III ——线段树
SPOJ GSS5 Can you answer these queries V ——线段树