牛客-小H的詢問(線段樹)

原題鏈接:更好的閱讀體驗
題目描述
小H給你一個數組{a},要求支持以下兩種操作:

  1. 0 l r(1<=l<=r<=n),詢問區間[l,r]中權值和最大的有效子區間的權值和,一個子區間被認爲是有效的當且僅當這個子區間中沒有兩個相鄰的偶數或者奇數。

  2. 1 x v(1<=x<=n,-109<=v<=109),將a[x]的值修改爲v。

輸入描述:
第一行讀入兩個正整數n,m(1<=n,m<=105)

第二行讀入n個整數,第i個表示a[i](-109 <= a[i] <= 109)

接下來m行,每行三個數表示操作,描述見題目描述。

輸出描述:
輸出每個詢問的答案。
示例1
輸入
複製
10 10
-9 -8 -8 -8 2 -7 -5 2 2 3
0 3 5
0 4 4
0 2 4
1 6 6
1 1 6
1 5 9
0 1 2
1 5 -8
0 2 4
1 3 -2
輸出
複製
2
-8
-8
6
-8
思路:
一般用線段樹的話,就是通過增加維護的東西來達到目的,這個題比維護最大連續子段和的題多了一個限制奇偶的條件,只需要在結構體中加入flag標記即可。

/**
用線段樹維護一個區間的和,
區間是否有效,
區間的左端和右端的奇偶性,
區間左端和右端開始的最大的有效子區間的和,
區間裏最大的有效子區間的和,
**/

ps:以後還是少用結構體全部賦值,少了個v找了半小時bug

代碼:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline void read(ll &x){
   ll s = 0, w = 1; char ch = getchar();
   while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar(); }
   while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
   x = s*w;
}
const int maxn=1e6+7;
struct node{
    ll flag;///該區間是否有效
    ll sum;///區間的和
    ll suml,sumr,maxsum;///左端開始的最大有效子區間和,右端,總的
    ll flagl,flagr;///左右區間的奇偶:1奇0偶
}a[maxn*4];
ll n,m;
ll vis[maxn];
void pushup(ll u){
    auto l=a[u<<1],r=a[u<<1|1],&x=a[u];
    x.flag=0;
    x.maxsum=max(l.maxsum,r.maxsum);///維護區間有效最大值
    x.flagl=l.flagl;x.flagr=r.flagr;///維護區間端點的奇偶性
    x.suml=l.suml;x.sumr=r.sumr;///維護左端開始的最大有效子區間和
   ///以上都是區間未合併時的情況
    if(l.flagr^r.flagl){///區間可合併
        x.maxsum=max(x.maxsum,l.sumr+r.suml);
        if(r.flag) x.sumr=max(x.sumr,l.sumr+r.sum);
        ///如果右邊區間合法,總區間的從右端區間開始的合法區間是右邊區間和左邊區間的從右開始的合法部分
        if(l.flag) x.suml=max(x.suml,r.suml+l.sum);
        if(l.flag&&r.flag){
            x.flag=1;
            x.sum=l.sum+r.sum;
        }
    }
}
node qupdate(node l,node r){
    node x;
    x.flag=0;
    x.maxsum=max(l.maxsum,r.maxsum);///維護區間有效最大值
    x.flagl=l.flagl;x.flagr=r.flagr;///維護區間端點的奇偶性
    x.suml=l.suml;x.sumr=r.sumr;///維護左端開始的最大有效子區間和
   ///以上都是區間未合併時的情況
    if(l.flagr^r.flagl){///區間可合併
        x.maxsum=max(x.maxsum,l.sumr+r.suml);
        if(r.flag) x.sumr=max(x.sumr,l.sumr+r.sum);
        ///如果右邊區間合法,總區間的從右端區間開始的合法區間是右邊區間和左邊區間的從右開始的合法部分
        if(l.flag) x.suml=max(x.suml,r.suml+l.sum);
        if(l.flag&&r.flag){
            x.flag=1;
            x.sum=l.sum+r.sum;
        }
    }
    return x;
}
void build(ll u,ll l,ll r){
    if(l==r)
        a[u]={1,vis[l],vis[l],vis[l],vis[l],vis[l]&1,vis[l]&1};
    else{
        int mid=(l+r)>>1;
        build(u<<1,l,mid);build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
/**
struct node{
    bool flag;///該區間是否有效
    ll sum;///區間的和
    ll suml,sumr,maxsum;///左端開始的最大有效子區間和,右端,總的
    bool flagl,flagr;///左右區間的奇偶:1奇0偶
}a[maxn*4];
**/
void update(int u,int l,int r,int x,int v){
    if(l==r)
        a[u]={1,v,v,v,v,v&1,v&1};
    else{
        int mid=(l+r)>>1;
        if(x<=mid) update(u<<1,l,mid,x,v);
        else update(u<<1|1,mid+1,r,x,v);
        pushup(u);
    }
}
node qask(int u,int l,int r,int x,int y){
    if(x<=l&&y>=r) return a[u];
    int mid=(l+r)>>1;
    if(y<=mid) return qask(u<<1,l,mid,x,y);
    else if(x>mid) return qask(u<<1|1,mid+1,r,x,y);
    else return qupdate(qask(u<<1,l,mid,x,y),qask(u<<1|1,mid+1,r,x,y));
}
int main(){
    cin>>n>>m;
    for(ll i=1;i<=n;i++) cin>>vis[i];
    build(1,1,n);
    ll op,x,y;
    while(m--){
        cin>>op>>x>>y;
        if(!op) printf("%lld\n",qask(1,1,n,x,y).maxsum);
        else update(1,1,n,x,y);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章