【SPOJ】 GSS系列 [线段树][动态区间求最大子段和]
SP1043 GSS1 - Can you answer these queries I 动态区间求最大子段和
动态区间求最大子段和
维护当前区间的和sum 最大前缀和lmx 最大后缀和rmx 最大子段和
洛谷第一篇题解那个dalao码风很赞 当成模板
重点在于查询,这里使用了结构体类型定义函数,这样写更加简洁,分情况查询,查询区间左端点在mid右,右端点在mid左,查询区间覆盖节点,查询区间被节点左右区间包含,合并查询类似于PushUp的操作,还是看代码理解
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register #define lson o<<1 #define rson o<<1|1 const int N=200000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827; int n,q,a[N]; char op; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } struct SegmentTree{ int sum,lmx,rmx,mxs; }tree[N<<1]; void pushup(int o){ tree[o].sum=tree[lson].sum+tree[rson].sum; tree[o].lmx=Max(tree[lson].lmx,tree[lson].sum+tree[rson].lmx);//最大前缀和 tree[o].rmx=Max(tree[rson].rmx,tree[rson].sum+tree[lson].rmx);//最大后缀和 tree[o].mxs=Max(Max(tree[lson].mxs,tree[rson].mxs),tree[lson].rmx+tree[rson].lmx); } void buildtree(int o,int l,int r){ if(l==r) {tree[o].sum=tree[o].mxs=tree[o].lmx=tree[o].rmx=a[l];return;} int mid=l+r>>1; buildtree(lson,l,mid),buildtree(rson,mid+1,r); pushup(o); } SegmentTree query(int o,int l,int r,int x,int y){ if(x<=l&&r<=y) return tree[o]; int mid=(l+r)>>1; if(y<=mid) return query(lson,l,mid,x,y);//完全位于左区间 else if(x>mid) return query(rson,mid+1,r,x,y);//完全位于右区间 else{//与左、右区间都有交集 SegmentTree ls,rs,ans; ls=query(lson,l,mid,x,y),rs=query(rson,mid+1,r,x,y); ans.sum=ls.sum+rs.sum; ans.lmx=Max(ls.lmx,ls.sum+rs.lmx); ans.rmx=Max(rs.rmx,rs.sum+ls.rmx); ans.mxs=Max(Max(ls.mxs,rs.mxs),ls.rmx+rs.lmx); return ans; } } int main(){ rd(n); for(int i=1;i<=n;++i) rd(a[i]); buildtree(1,1,n); rd(q); for(int i=1,x,y;i<=q;++i){ rd(x),rd(y); printf("%d\n",query(1,1,n,x,y).mxs); } return 0; }
SP1557 GSS2 - Can you answer these queries II
给出n 个数,q 次询问,求最大子段和,相同的数只算一次
你鲨了我叭 一堆细节 考场打死我都调不出来 就比上面那题多了一个条件 难度蹭蹭上涨
维护一段区间的sum historymaxsum 还有tag:add maxadd
就像[SDOI2009]HH的项链一样有要求去重 我们得考虑离线来做
然后就是1mol的细节 结合代码好好思考 题还是个好题QAQ
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<cmath> #include<stack> #include<algorithm> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register #define lson o<<1 #define rson o<<1|1 const int N=100000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827; ll n,m,a[N],pre[N],id[N<<1],ans[N]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } struct SegmentTree{ ll hismx,sum,add,mxadd; SegmentTree(){hismx=sum=add=mxadd=0;} }tree[N<<2]; void pushdown(int o){//注意这几个的更新顺序 tree[lson].hismx=Max(tree[lson].hismx,tree[lson].sum+tree[o].mxadd); tree[rson].hismx=Max(tree[rson].hismx,tree[rson].sum+tree[o].mxadd); //historymaxsum用儿子的sum+节点historymaxtag来更新 tree[lson].sum+=tree[o].add,tree[rson].sum+=tree[o].add; tree[lson].mxadd=Max(tree[lson].mxadd,tree[o].mxadd+tree[lson].add); tree[rson].mxadd=Max(tree[rson].mxadd,tree[o].mxadd+tree[rson].add); //historymaxtag用儿子的sumtag+节点historymaxtag tree[lson].add+=tree[o].add,tree[rson].add+=tree[o].add; tree[o].mxadd=tree[o].add=0; } void pushup(int o){ tree[o].sum=Max(tree[lson].sum,tree[rson].sum); tree[o].hismx=Max(tree[lson].hismx,tree[rson].hismx); } void update(int o,int l,int r,int x,int y,ll k){ if(r<x||l>y) return; if(x<=l&&r<=y){//在区间内 tree[o].sum+=k; tree[o].hismx=Max(tree[o].hismx,tree[o].sum); tree[o].add+=k; tree[o].mxadd=Max(tree[o].mxadd,tree[o].add); return; } pushdown(o); int mid=l+r>>1; update(lson,l,mid,x,y,k),update(rson,mid+1,r,x,y,k); pushup(o); } SegmentTree query(int o,int l,int r,int x,int y){ if(x<=l&&r<=y) return tree[o]; pushdown(o); int mid=l+r>>1; if(y<=mid) return query(lson,l,mid,x,y);//完全在左边 else if(x>mid) return query(rson,mid+1,r,x,y);//完全在右边 else{ SegmentTree ans,ls,rs; ls=query(lson,l,mid,x,y),rs=query(rson,mid+1,r,x,y); ans.hismx=Max(ls.hismx,rs.hismx); return ans; } } struct node{int x,y,pos;}ask[N]; bool cmp(node x,node y){return x.y<y.y;} int main(){ // freopen("in.txt","r",stdin); rd(n); for(int i=1;i<=n;++i) rd(a[i]),pre[i]=id[a[i]+N],id[a[i]+N]=i; rd(m); for(int i=1;i<=m;++i) rd(ask[i].x),rd(ask[i].y),ask[i].pos=i; sort(ask+1,ask+1+m,cmp); int pos=1; for(int i=1;i<=n;++i){ update(1,1,n,pre[i]+1,i,a[i]); for(;pos<=m&&ask[pos].y<=i;++pos){ ans[ask[pos].pos]=query(1,1,n,ask[pos].x,ask[pos].y).hismx; } } for(int i=1;i<=m;++i) printf("%lld\n",ans[i]); return 0; }
SP1716 GSS3 - Can you answer these queries III 动态区间求最大子段和+单点修改
其实是一样的 然后单点修改又和buildtree长得差不多
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register #define lson o<<1 #define rson o<<1|1 const int N=200000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827; int n,q,a[N]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } struct SegmentTree{int sum,lmx,rmx,mxs;}tree[N]; void pushup(int o){ tree[o].sum=tree[lson].sum+tree[rson].sum; tree[o].lmx=Max(tree[lson].lmx,tree[lson].sum+tree[rson].lmx); tree[o].rmx=Max(tree[rson].rmx,tree[rson].sum+tree[lson].rmx); tree[o].mxs=Max(Max(tree[lson].mxs,tree[rson].mxs),tree[lson].rmx+tree[rson].lmx); } void buildtree(int o,int l,int r){ if(l==r){tree[o].sum=tree[o].lmx=tree[o].rmx=tree[o].mxs=a[l];return;} int mid=l+r>>1; buildtree(lson,l,mid),buildtree(rson,mid+1,r); pushup(o); } void modify(int o,int l,int r,int x,int k){ if(l==r){tree[o].sum=tree[o].lmx=tree[o].rmx=tree[o].mxs=k;return;} int mid=l+r>>1; if(x<=mid) modify(lson,l,mid,x,k); else modify(rson,mid+1,r,x,k); pushup(o); } SegmentTree query(int o,int l,int r,int x,int y){ if(x<=l&&r<=y) return tree[o]; int mid=l+r>>1; if(y<=mid) return query(lson,l,mid,x,y); else if(x>mid) return query(rson,mid+1,r,x,y); else{ SegmentTree ls,rs,ans; ls=query(lson,l,mid,x,y),rs=query(rson,mid+1,r,x,y); ans.sum=ls.sum+rs.sum; ans.lmx=Max(ls.lmx,ls.sum+rs.lmx); ans.rmx=Max(rs.rmx,rs.sum+ls.rmx); ans.mxs=Max(Max(ls.mxs,rs.mxs),ls.rmx+rs.lmx); return ans; } } int main(){ rd(n); for(int i=1;i<=n;++i) rd(a[i]); buildtree(1,1,n); rd(q); for(int i=1,x,y,op;i<=q;++i){ rd(op),rd(x),rd(y); if(op==1) printf("%d\n",query(1,1,n,x,y).mxs); else modify(1,1,n,x,y); } return 0; }
SP2713 GSS4 - Can you answer these queries IV 线段树求区间和 区间开方
和花神游历各国是一样的 只是我死于输出.... 开始忘了Case #1后面的: 然后找到了一激动 改成Case #%d\n: 我还有什么话可说呢QAQ
/* Case #1后面有个:!!!QAQ */ #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register #define lson o<<1 #define rson o<<1|1 const int N=100000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827; int n,m,cas=0; ll a[N],sum[N<<2],mx[N<<2]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } void pushup(int o){ sum[o]=sum[lson]+sum[rson]; mx[o]=Max(mx[lson],mx[rson]); } void update(int o,int l,int r,int x,int y){ if(r<x||l>y) return; if(mx[o]<=1&&x<=l&&r<=y) return; if(l==r) {mx[o]=sum[o]=floor(sqrt(sum[o]));return;} int mid=l+r>>1; update(lson,l,mid,x,y),update(rson,mid+1,r,x,y); pushup(o); } ll query(int o,int l,int r,int x,int y){ if(r<x||l>y) return 0; if(x<=l&&r<=y) return sum[o]; int mid=l+r>>1;ll ans=0; ans+=query(lson,l,mid,x,y);ans+=query(rson,mid+1,r,x,y); return ans; } void buildtree(int o,int l,int r){ if(l==r) {sum[o]=mx[o]=a[l];return;} int mid=l+r>>1; buildtree(lson,l,mid),buildtree(rson,mid+1,r); pushup(o); } int main(){ // freopen("in.txt","r",stdin); while(scanf("%lld",&n)==1){ printf("Case #%d:\n",++cas); for(int i=1;i<=n;++i) rd(a[i]); buildtree(1,1,n); rd(m); for(int i=1,op,x,y;i<=m;++i){ rd(op),rd(x),rd(y); if(x>y) swap(x,y); if(op==1) printf("%lld\n",query(1,1,n,x,y)); else update(1,1,n,x,y); } puts(""); } return 0; }
SP2916 GSS5 - Can you answer these querie
给定一个序列。查询左端点在[x1, y1]之间,且右端点在[x2, y2]之间的最大子段和,数据保证x1≤x2,y1≤y2,但是不保证端点所在的区间不重合
考虑这个的情况我真的要考虑die了 我开始是把所有的情况都讨论出来QAQ 其实在query查询时加一个判断为空就好了
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define Max(x,y) (x)>(y)?(x):(y) #define Min(x,y) (x)>(y)?(y):(x) #define ll long long #define rg register #define lson o<<1 #define rson o<<1|1 const int N=200000+5,M=1000000+5,inf=0x3f3f3f3f,P=19650827; int T,n,q,a[N]; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } struct SegmentTree{ int sum,lmx,rmx,mxs; SegmentTree(){sum=lmx=rmx=mxs=0;} }tree[N<<1],blank; void pushup(int o){ tree[o].sum=tree[lson].sum+tree[rson].sum; tree[o].lmx=Max(tree[lson].lmx,tree[lson].sum+tree[rson].lmx);//最大前缀和 tree[o].rmx=Max(tree[rson].rmx,tree[rson].sum+tree[lson].rmx);//最大后缀和 tree[o].mxs=Max(Max(tree[lson].mxs,tree[rson].mxs),tree[lson].rmx+tree[rson].lmx); } void buildtree(int o,int l,int r){ if(l==r) {tree[o].sum=tree[o].mxs=tree[o].lmx=tree[o].rmx=a[l];return;} int mid=l+r>>1; buildtree(lson,l,mid),buildtree(rson,mid+1,r); pushup(o); } SegmentTree query(int o,int l,int r,int x,int y){ if(x>y) return blank; if(x<=l&&r<=y) return tree[o]; int mid=(l+r)>>1; if(y<=mid) return query(lson,l,mid,x,y);//完全位于左区间 else if(x>mid) return query(rson,mid+1,r,x,y);//完全位于右区间 else{//与左、右区间都有交集 SegmentTree ls,rs,ans; ls=query(lson,l,mid,x,y),rs=query(rson,mid+1,r,x,y); ans.sum=ls.sum+rs.sum; ans.lmx=Max(ls.lmx,ls.sum+rs.lmx); ans.rmx=Max(rs.rmx,rs.sum+ls.rmx); ans.mxs=Max(Max(ls.mxs,rs.mxs),ls.rmx+rs.lmx); return ans; } } int main(){ // freopen("in.txt","r",stdin); rd(T); while(T--){ rd(n); for(int i=1;i<=n;++i) rd(a[i]); buildtree(1,1,n); rd(q); int x1,y1,x2,y2,ans,ans1; for(int i=1;i<=q;++i){ rd(x1),rd(y1),rd(x2),rd(y2),ans=0; if(y1<x2){ ans+=query(1,1,n,y1,x2).sum; ans+=Max(query(1,1,n,x1,y1-1).rmx,0); ans+=Max(query(1,1,n,x2+1,y2).lmx,0); } else{ ans=query(1,1,n,x2,y1).mxs; ans=Max(ans,query(1,1,n,x2,y1).lmx +query(1,1,n,x1,x2-1).rmx); ans=Max(ans,query(1,1,n,y1+1,y2).lmx+query(1,1,n,x2,y1).rmx); ans1=query(1,1,n,x2,y1).sum;ans1+=Max(0,query(1,1,n,x1,x2-1).rmx);ans1+=Max(0,query(1,1,n,y1+1,y2).lmx); ans=Max(ans,ans1); } printf("%d\n",ans); } } return 0; }