线段树1
思路:
我们需要维护的东西是序列的最小值和最小值个数
这道题没有修改操作,因此不考虑修改
然后考虑Pushup
最小值很简单,直接取min
最小值个数怎么维护呢?考虑这个区间需要维护的值如何从左右两个区间获得
如果左右两个子区间的最小值相同,那么就可以直接相加
否则,如果这个区间的最小值是左区间最小值,直接赋值左区间的
否则就是右区间的
学一学dls的代码风格,感觉很高级QwQ
Code:
#include <bits/stdc++.h>#define int long longusing namespace std;const int mxn=2e5+10;
const int mxe=2e5+10;struct info{int minv,mincnt;
};info operator+(const info &l,const info &r){info a;a.minv=min(l.minv,r.minv);if(l.minv==r.minv) a.mincnt=l.mincnt+r.mincnt;else if(l.minv<r.minv) a.mincnt=l.mincnt;else a.mincnt=r.mincnt;return a;
}struct ty{info val;
}tree[mxe<<2];int n,Q,x,d,l,r,op;
int a[mxn]; void pushup(int rt){tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
}
void build(int rt,int l,int r){if(l==r){tree[rt].val={a[l],1};return;}int mid=l+r>>1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);pushup(rt);
}
info query(int rt,int l,int r,int x,int y){if(x<=l&&r<=y){return tree[rt].val;}int mid=l+r>>1;if(y<=mid) return query(rt<<1,l,mid,x,y);else if(x>mid) return query(rt<<1|1,mid+1,r,x,y);else{return query(rt<<1,l,mid,x,y)+query(rt<<1|1,mid+1,r,x,y);}
}
void change(int rt,int l,int r,int x,int k){if(l==r){tree[rt].val={k,1};return;}int mid=l+r>>1;if(x<=mid) change(rt<<1,l,mid,x,k);else change(rt<<1|1,mid+1,r,x,k);pushup(rt);
}
void solve(){cin>>n>>Q;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);while(Q--){cin>>op;if(op==1){cin>>x>>d;change(1,1,n,x,d);}else{cin>>l>>r;cout<<query(1,1,n,l,r).minv<<" "<<query(1,1,n,l,r).mincnt<<'\n';}}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int __=1;//cin>>__;while(__--)solve();return 0;
}
线段树2
题意:
思路:
我们需要维护一个区间的最大子段和
两个子区间的最大子段和怎么得到一整个区间的最大子段和呢
分类讨论即可
这个子段可能完全出现在左区间,也可能完全出现在右区间,也可能是左区间的右部分+右区间的左部分
前两种情况直接赋值即可
对于第三种情况,其实就是左区间的右部分最大子段和+右区间的左部分的最大子段和 之和
因此我们需要维护这两个值
然后开始考虑怎么维护
对于左部分最大子段和,它可能是左区间的左部分最大子段和,也有可能是左区间一整个区间+右区间的左部分最大子段和
右部分最大子段和同理
最后来看dls的板子,它需要写构造函数,因为我们这次在build的时候没有把所有的值都初始化
Code:
#include <bits/stdc++.h>#define int long longusing namespace std;const int mxn=2e5+10;
const int mxe=2e5+10;struct info{int mss,mpre,msuf,s;info(){}info(int a) :mss(a),mpre(a),msuf(a),s(a){}
};info operator+(const info &l,const info &r){info a;a.s=l.s+r.s;a.mss=max(max(l.mss,r.mss),l.msuf+r.mpre);a.mpre=max(l.mpre,l.s+r.mpre);a.msuf=max(r.msuf,r.s+l.msuf);return a;
}struct ty{info val;
}tree[mxe<<2];int n,Q,x,d,l,r,op;
int a[mxn]; void pushup(int rt){tree[rt].val=tree[rt<<1].val+tree[rt<<1|1].val;
}
void build(int rt,int l,int r){if(l==r){tree[rt].val=info(a[l]);return;}int mid=l+r>>1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);pushup(rt);
}
info query(int rt,int l,int r,int x,int y){if(x<=l&&r<=y){return tree[rt].val;}int mid=l+r>>1;if(y<=mid) return query(rt<<1,l,mid,x,y);else if(x>mid) return query(rt<<1|1,mid+1,r,x,y);else{return query(rt<<1,l,mid,x,y)+query(rt<<1|1,mid+1,r,x,y);}
}
void change(int rt,int l,int r,int x,int k){if(l==r){tree[rt].val=info(k);return;}int mid=l+r>>1;if(x<=mid) change(rt<<1,l,mid,x,k);else change(rt<<1|1,mid+1,r,x,k);pushup(rt);
}
void solve(){cin>>n>>Q;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);while(Q--){cin>>op;if(op==1){cin>>x>>d;change(1,1,n,x,d);}else{cin>>l>>r;cout<<query(1,1,n,l,r).mss<<'\n';}}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int __=1;//cin>>__;while(__--)solve();return 0;
}
线段树打标记
题意:
思路:
我们需要维护的是最大值,这个很好维护,Pushup直接取max即可
问题是需要区间修改,区间加
这个加个add标记即可,在Pushdown的时候更新mx属性
这种打标记的最重要的是如何在Pushdown的时候观察区间修改操作如何影响需要维护的值
在这里很简单,直接最大值mx使加上add即可
Code:
#include <bits/stdc++.h>#define int long longusing namespace std;const int mxn=2e5+10;
const int mxe=2e5+10;struct Segtree{int mx,add;
}tree[mxe<<2];int n,Q,x,d,l,r,op;
int a[mxn]; void settag(int rt,int t){tree[rt].add+=t;tree[rt].mx+=t;
}
void pushup(int rt){tree[rt].mx=max(tree[rt<<1].mx,tree[rt<<1|1].mx);
}
void pushdown(int rt){if(tree[rt].add){settag(rt<<1,tree[rt].add);settag(rt<<1|1,tree[rt].add);tree[rt].add=0;}
}
void build(int rt,int l,int r){if(l==r){tree[rt]={a[l],0};return;}int mid=l+r>>1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);pushup(rt);
}
int query(int rt,int l,int r,int ql,int qr){if(ql<=l&&r<=qr){return tree[rt].mx;}pushdown(rt);int mid=l+r>>1;if(qr<=mid) return query(rt<<1,l,mid,ql,qr);else if(ql>mid) return query(rt<<1|1,mid+1,r,ql,qr);else{return max(query(rt<<1,l,mid,ql,qr),query(rt<<1|1,mid+1,r,ql,qr));}
}
void modify(int rt,int l,int r,int ql,int qr,int d){if(ql<=l&&r<=qr){settag(rt,d);return;}pushdown(rt);int mid=l+r>>1;if(qr<=mid) modify(rt<<1,l,mid,ql,qr,d);else if(ql>mid) modify(rt<<1|1,mid+1,r,ql,qr,d);else{modify(rt<<1,l,mid,ql,qr,d);modify(rt<<1|1,mid+1,r,ql,qr,d);}pushup(rt);
}
void solve(){cin>>n>>Q;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);while(Q--){cin>>op;if(op==1){cin>>l>>r>>d;modify(1,1,n,l,r,d);}else{cin>>l>>r;cout<<query(1,1,n,l,r)<<'\n';}}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int __=1;//cin>>__;while(__--)solve();return 0;
}
线段树打标记2
题意:
Code:
#include <bits/stdc++.h>#define int long longusing namespace std;const int mxn=2e5+10;
const int mxe=2e5+10;
const int mod=1e9+7;struct tag{int mul,add;
};tag operator+(const tag &l,const tag &r){return {(l.mul*r.mul)%mod,(l.add*r.mul+r.add)%mod};
}
struct Segtree{tag t;int val;int sz;
}tree[mxe<<2];int n,Q,x,d,l,r,op;
int a[mxn]; void settag(int rt,tag t){tree[rt].t=tree[rt].t+t;tree[rt].val=(tree[rt].val*t.mul+tree[rt].sz*t.add)%mod;
}
void pushup(int rt){tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%mod;
}
void pushdown(int rt){if(tree[rt].t.mul!=1||tree[rt].t.add!=0){settag(rt<<1,tree[rt].t);settag(rt<<1|1,tree[rt].t);tree[rt].t={1,0};}
}
void build(int rt,int l,int r){tree[rt].t={1,0};tree[rt].sz=r-l+1;if(l==r){tree[rt].val=a[l];return;}int mid=l+r>>1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);pushup(rt);
}
int query(int rt,int l,int r,int ql,int qr){if(ql<=l&&r<=qr){return tree[rt].val;}pushdown(rt);int mid=l+r>>1;if(qr<=mid) return query(rt<<1,l,mid,ql,qr);if(ql>mid) return query(rt<<1|1,mid+1,r,ql,qr);return (query(rt<<1,l,mid,ql,qr)+query(rt<<1|1,mid+1,r,ql,qr))%mod;
}
void modify(int rt,int l,int r,int ql,int qr,tag t){if(ql==l&&r==qr){settag(rt,t);return;}pushdown(rt);int mid=l+r>>1;if(qr<=mid) modify(rt<<1,l,mid,ql,qr,t);else if(ql>mid) modify(rt<<1|1,mid+1,r,ql,qr,t);else{modify(rt<<1,l,mid,ql,mid,t);modify(rt<<1|1,mid+1,r,mid+1,qr,t);}pushup(rt);
}
void solve(){cin>>n>>Q;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);while(Q--){cin>>op;if(op==1){cin>>l>>r>>d;modify(1,1,n,l,r,(tag){1,d});}else if(op==2){cin>>l>>r>>d;modify(1,1,n,l,r,(tag){d,0});}else if(op==3){cin>>l>>r>>d;modify(1,1,n,l,r,(tag){0,d});}else{cin>>l>>r;cout<<query(1,1,n,l,r)<<'\n';}}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int __=1;//cin>>__;while(__--)solve();return 0;
}