1. 程式人生 > >【Wannafly挑戰賽10】D.小H的詢問(線段樹的區間合併)

【Wannafly挑戰賽10】D.小H的詢問(線段樹的區間合併)

記錄一個菜逼的成長。。

題目連結
來源:牛客網

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld

題目描述

小H給你一個數組{a},要求支援以下兩種操作:

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

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

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

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

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

輸出描述:
輸出每個詢問的答案。

分析

算是經典的線段樹的區間合併。
可以說是模板題了吧。

先說結點的結構。
記錄區間的左右邊界的l,r;
記錄區間[l,r]的所有數的和sum
記錄在區間[l,r]裡最左邊的有效區間,即包含左端點的有效區間的值sl,和最右邊的有效區間的值sr
記錄區間[l,r]裡有效區間的最大值ans

重點在如何合併。
現在有兩個區間[l1,r1],[l2,r2]
ar1al2不互為偶數或奇數時,
兩區間可以合併。


此時合併後的區間[l1,r2]sl
max(sl1,sum1+sl2)
這裡包含了兩層意思。
如果區間[l1,r1]為有效區間,sum為區間和,max自然會取後值。
如果區間[l1,r1]不為有效區間,sum會被設為-INF,max自然會取前值。
同理sr=max(sr2,sum2+sr1)
ans=max(max(ans1,ans2),sr1+sl2)

反之兩區間不可以合併
sum被設為-INF,與合併時的操作相對應
sl=sl1,sr=sr2
ans=max(ans1,ans2)

#include <bits/stdc++.h>
using namespace
std; #define pb push_back #define mp make_pair #define fi first #define se second #define cl(a,b) memset(a,b,sizeof(a)) #define clr clear() #define lson t<<1,l,mid #define rson t<<1|1,mid+1,r #define seglen(t) (node[t].r-node[t].l+1) typedef long long LL; typedef pair<LL,LL> PLL; typedef pair<int,int> PII; const LL INF = 0x3f3f3f3f; const int maxn = 100000 + 10; LL a[maxn]; struct Node{ int l,r; LL sl,sr; LL ans,sum; Node(){l = r = 0;sum = -INF * maxn;} Node operator + (const Node &ob)const { Node ret ; ret.l = l;ret.r = ob.r; if((a[r]^a[ob.l])&1) { ret.sum = sum + ob.sum; ret.sl = max(sl,sum + ob.sl); ret.sr = max(ob.sr,ob.sum + sr); ret.ans = max(max(ans,ob.ans),sr + ob.sl); } else { ret.sum = -INF * maxn; ret.sl = sl;ret.sr = ob.sr; ret.ans = max(ans,ob.ans); } return ret; } }node[maxn<<2]; void pushup(int t) { node[t] = node[t<<1] + node[t<<1|1]; } void build(int t,int l,int r) { node[t].l = l; node[t].r = r; node[t].sum = -INF * maxn; if (l == r) { node[t].sl = node[t].sr = node[t].ans = node[t].sum = a[l]; return ; } int mid = (l + r) >> 1; build(lson); build(rson); pushup(t); } void update(int t,int ind,LL v) { if(node[t].l == node[t].r) { node[t].sl = node[t].sr = node[t].ans = node[t].sum = v; return ; } int mid = (node[t].l + node[t].r) >> 1; if(ind <= mid)update(t<<1,ind,v); if(ind > mid)update(t<<1|1,ind,v); pushup(t); } Node query(int t,int l,int r) { if(node[t].l >= l && r >= node[t].r) { return node[t]; } int mid = (node[t].l + node[t].r) >> 1; if(l > mid)return query(t<<1|1,l,r); if(r <= mid)return query(t<<1,l,r); return query(t<<1,l,r) + query(t<<1|1,l,r); } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for (int i = 1; i <= n; i++) scanf("%lld",a+i); build(1,1,n); while(m--) { int ope,l,r; scanf("%d%d%d",&ope,&l,&r); if(ope) { a[l] = r; update(1,l,(LL)r); } else { Node ret = query(1,l,r); printf("%lld\n",ret.ans); } } } return 0; }