线段树1
思路:
我们需要维护的东西是序列的最小值和最小值个数
这道题没有修改操作,因此不考虑修改
然后考虑Pushup
最小值很简单,直接取min
最小值个数怎么维护呢?考虑这个区间需要维护的值如何从左右两个区间获得
如果左右两个子区间的最小值相同,那么就可以直接相加
否则,如果这个区间的最小值是左区间最小值,直接赋值左区间的
否则就是右区间的
学一学dls的代码风格,感觉很高级QwQ
Code:
#include <bits/stdc++.h>
#define int long long
using 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 long
using 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 long
using 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 long
using 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;
}