淺談一類線段樹轉移的問題
最近大概是泛做了線段樹相關題目,但是這些線段樹大概都需要比較強的思維和比較長的代碼……\(2333\)
$\rm{Task1} $子段和
其實這個算是比較簡單的了,畢竟\(qyf\)曾經給我們講過,當時我就覺得十分的……麻煩233.
那麽例題其實就是\(\rm{SPOJ}\)的\(GSS\)系列——的前三道題(後幾道題都不會做)
\(GSS1\)區間求最大子段和(不帶修)
\(Link\)
\(2333\)應該算是比較簡單的了,我們對於每個區間維護一個區間和,維護一個從最左端開始且必須包含最左端元素的最大子段和,再維護一個從最右端開始且必須包含最右端元素的最大子段和,最後維護一個區間最大子段和
那麽轉移(\(push\_up\))時就顯得十分方便。我們的父區間的\(Lmax\)只取決於左子區間的\(Lmax\)和當左區間的\(Sum\)等於\(Max\)時(即左區間全部都要納入到其最大子段和中時),左區間的\(Sum\)與右區間的\(Lmax\)的和。那麽對於區間的\(Rsum\),也是一個道理。最終對於該區間的最大子段和,我們不考慮從已經轉移來的\(Lmax/Rmax\),而是考慮從左右區間的\(Max\)以及左右區間的和來轉移。大體代碼:
inline void P_u(int rt){ S(rt) = S(ls(rt)) + S(rs(rt)) ; Lsum(rt) = max(Lsum(ls(rt)), S(ls(rt)) + Lsum(rs(rt))) ; Rsum(rt) = max(Rsum(rs(rt)), S(rs(rt)) + Rsum(ls(rt))) ; Sum(rt) = max(max(Sum(ls(rt)), Sum(rs(rt))), Lsum(rs(rt)) + Rsum(ls(rt))) ; }
還有值得註意的一點:在詢問的時候,它比較膈應……就是由於是連續的,所以你不能直接像普通的線段樹一樣詢問然後加起來……所以所就要類似於邊詢問,邊\(push\_up\)這種感覺。
Tree query(int rt, int l, int r){ if (L <= l && r <= R) return T[rt] ; Tree res, A, B ; if (mid >= R) return query(ls(rt), l, mid) ; if (mid < L) return query(rs(rt), mid + 1, r) ; A = query(ls(rt), l, mid), B = query(rs(rt), mid + 1, r) ; res.Lsum = max(A.Lsum, A.S + B.Lsum) ; res.Rsum = max(B.Rsum, B.S + A.Rsum) ; res.Sum = max(max(A.Sum, B.Sum), A.Rsum + B.Lsum) ; res.S = A.S + B.S ; return res ; }
然後總代碼:
#include <cstdio>
#include <iostream>
#define MAXN 200010
#define LL long long
#define max my_Fuckmax
#define ls(rt) rt << 1
#define rs(rt) rt << 1 | 1
#define mid ((l + r) >> 1)
using namespace std ;
struct Tree{
LL S, Sum, Lsum, Rsum ;
}T[MAXN << 1] ; int N, M, L, R, base[MAXN] ;
#define S(x) T[x].S
#define Sum(x) T[x].Sum
#define Lsum(x) T[x].Lsum
#define Rsum(x) T[x].Rsum
inline LL my_Fuckmax(LL A, LL B){
return A & ((B - A) >> 63) | B & ((~(B - A)) >> 63) ;
}
inline void P_u(int rt){
S(rt) = S(ls(rt)) + S(rs(rt)) ;
Lsum(rt) = max(Lsum(ls(rt)), S(ls(rt)) + Lsum(rs(rt))) ;
Rsum(rt) = max(Rsum(rs(rt)), S(rs(rt)) + Rsum(ls(rt))) ;
Sum(rt) = max(max(Sum(ls(rt)), Sum(rs(rt))), Lsum(rs(rt)) + Rsum(ls(rt))) ;
}
inline void build(int rt, int l, int r){
if (l == r){
T[rt].Lsum = T[rt].Rsum =
T[rt].S = T[rt].Sum = base[l] ; return ;
} build(ls(rt), l, mid), build(rs(rt), mid + 1, r), P_u(rt) ;
}
Tree query(int rt, int l, int r){
if (L <= l && r <= R)
return T[rt] ;
Tree res, A, B ;
if (mid >= R) return query(ls(rt), l, mid) ;
if (mid < L) return query(rs(rt), mid + 1, r) ;
A = query(ls(rt), l, mid), B = query(rs(rt), mid + 1, r) ;
res.Lsum = max(A.Lsum, A.S + B.Lsum) ; res.Rsum = max(B.Rsum, B.S + A.Rsum) ;
res.Sum = max(max(A.Sum, B.Sum), A.Rsum + B.Lsum) ; res.S = A.S + B.S ; return res ;
}
int main(){
cin >> N ; register int i ;
for (i = 1 ; i <= N ; ++ i) scanf("%d", &base[i]) ; build(1, 1, N) ; cin >> M ;
while (M --) scanf("%d%d", &L, &R), printf("%lld\n", query(1, 1, N).Sum) ; return 0 ;
}
\(GSS3\)區間求最大子段和(帶修)
\(Link\)
……其實吧,這個帶修不帶修……好像影響並不大?
#include <cstdio>
#include <iostream>
#define MAXN 200010
#define LL long long
#define max my_Fuckmax
#define ls(rt) rt << 1
#define rs(rt) rt << 1 | 1
#define mid ((l + r) >> 1)
using namespace std ;
bool MArk ;
struct Tree{
LL S, Sum, Lsum, Rsum ;
}T[MAXN << 1] ; int N, M, L, R, base[MAXN] ;
#define S(x) T[x].S
#define Sum(x) T[x].Sum
#define Lsum(x) T[x].Lsum
#define Rsum(x) T[x].Rsum
inline LL my_Fuckmax(LL A, LL B){
return A & ((B - A) >> 63) | B & ((~(B - A)) >> 63) ;
}
inline void P_u(int rt){
S(rt) = S(ls(rt)) + S(rs(rt)) ;
Lsum(rt) = max(Lsum(ls(rt)), S(ls(rt)) + Lsum(rs(rt))) ;
Rsum(rt) = max(Rsum(rs(rt)), S(rs(rt)) + Rsum(ls(rt))) ;
Sum(rt) = max(max(Sum(ls(rt)), Sum(rs(rt))), Lsum(rs(rt)) + Rsum(ls(rt))) ;
}
inline void build(int rt, int l, int r){
if (l == r){
T[rt].Lsum = T[rt].Rsum =
T[rt].S = T[rt].Sum = base[l] ; return ;
} build(ls(rt), l, mid), build(rs(rt), mid + 1, r), P_u(rt) ;
}
Tree query(int rt, int l, int r){
if (L <= l && r <= R)
return T[rt] ;
Tree res, A, B ;
if (mid >= R) return query(ls(rt), l, mid) ;
if (mid < L) return query(rs(rt), mid + 1, r) ;
A = query(ls(rt), l, mid), B = query(rs(rt), mid + 1, r) ;
res.Lsum = max(A.Lsum, A.S + B.Lsum) ; res.Rsum = max(B.Rsum, B.S + A.Rsum) ;
res.Sum = max(max(A.Sum, B.Sum), A.Rsum + B.Lsum) ; res.S = A.S + B.S ; return res ;
}
inline void change(int rt, int l, int r, int k){
if (L == l && L == r){
T[rt].Sum = T[rt].Lsum = T[rt].Rsum = T[rt].S = k ; return ;
}
if (L <= mid) change(ls(rt), l, mid, k) ;
else change(rs(rt), mid + 1, r, k ) ; P_u(rt) ;
}
int main(){
cin >> N ; register int i ;
for (i = 1 ; i <= N ; ++ i) scanf("%d", &base[i]) ; build(1, 1, N) ; cin >> M ;
while (M --) {
scanf("%d%d%d", &MArk, &L, &R) ;
if (!MArk) change(1, 1, N, R) ;
else printf("%lld\n", query(1, 1, N).Sum) ;
}
}
\(GSS4\)區間開根問題
\(Link\)
這個和子段和一點兒關系都沒有,順便整一下233.
就是讓你區間開根(向下取整)+查詢……這個東西大概就是對於一個\(2^{63}\)內的數值\(N\),我們假設其開根\(k\)次可以得到\(N < 2\)——只要\(N < 2\)之後的計算就會集中在一個緊確的範圍\((1,2)\)內,向下取整之後永遠都會是\(1\),所以我們不需要再去考慮。
那麽現在,我們致力於去確定\(k\)的值域。我們不得不承認,\(\sqrt n\)在\([0,+\infty]\)是單調遞增的,同理三次方根也是,四次方根也是……所以我們不妨取最大值,考慮\(N=2^{63}\)時,\(k\)值的大小。而很顯然,此時的\(k\)應該為\(\log _263+1 ≈ 6.978\)——這似乎是十分平凡的結論。
總之,我們得出,似乎運算次數的上界就是\(k≈7\),所以說我們直接暴力除就好了,聚合分析一下,復雜度的上界似乎是\(\Omega(7n)\)的樣子,無非就是多幾個常數。
#include <cmath>
#include <cstdio>
#include <iostream>
#define MAXN 500010
#define ll long long
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std ;
ll N, M, K, i, L, R ;
ll base[MAXN], T[MAXN], tot ;
inline ll qr(){
ll k = 0 ; char c = getchar() ;
while (!isdigit(c)) c = getchar() ;
while (isdigit(c)) k = k * 10 + c - 48, c = getchar() ;
return k ;
}
inline void p_u(ll rt){ ;}
void _Build(ll rt, ll l, ll r){
if (l == r){T[rt] = base[l] ; return ;}
_Build(ls(rt), l, mid) ;
_Build(rs(rt), mid + 1, r) ;
T[rt] = T[ls(rt)] + T[rs(rt)] ;
}
inline ll _query(ll rt, ll l, ll r, ll sl, ll sr){
if (l >= sl && r <= sr) return T[rt] ;
ll ret = 0 ;
if (mid >= sl) ret += _query(ls(rt), l, mid, sl, sr) ;
if (mid < sr) ret += _query(rs(rt), mid + 1, r, sl, sr) ;
return ret ;
}
inline void _Sqrt(ll rt, ll l, ll r, ll sl, ll sr){
if (l >= sl && r <= sr){
if (T[rt] <= (r - l + 1)) return ;
else {
if (l == r){
T[rt] = (int)(pow((double)T[rt], 0.5)) ;
return ;
}
}
}
if (mid >= sl) _Sqrt(ls(rt), l, mid, sl, sr),
T[rt] = T[ls(rt)] + T[rs(rt)] ;
if (mid < sr) _Sqrt(rs(rt), mid + 1, r, sl, sr),
T[rt] = T[ls(rt)] + T[rs(rt)] ;
}
int main(){
while(cin >> N){
++ tot, printf("Case #%d:\n", tot) ;
for (i = 1; i <= N ; ++ i) base[i] = qr() ;
_Build(1, 1, N) ; cin >> M ;
for (i = 1; i <= M ; ++ i){
K = qr(), L = qr(), R = qr() ;
if (L > R) swap(L, R) ;
if (K){
printf("%lld\n", _query(1, 1, N, L, R)) ;
continue ;
}
_Sqrt(1, 1, N, L, R) ;
}
printf("\n") ;
}
return 0 ;
}
\(\rm{Task2}\) 最長連續問題
這個東西其實應該跟最大子段和差不多——要求的都是連續的東西。對於所有包括連續字樣的東西,基本的思路大概都是維護一個從左端開始的,維護一個從右端開始的,然後從下向上不斷\(push_up\)即可。
\(emmm\)在這邊整理幾道思路不錯的題吧:
\(\rm{USACO}\) 酒店(\(hotel\))
\(Link\)
初始的一個全零的序列,我們對它準確來說有以下三個操作:
- 區間置\(0\)
- 區間置\(1\)
- 詢問是否有一段長度為\(k\)的連續的零區間,如果有的話,選取最靠左的,輸出其左端點並執行操作②
這個題在我看來,應該算是一個思維題。對於最後一個操作,我十分地懵逼——因為我壓根不知道該怎麽維護。
但事實上……這就是學數據結構學傻了的後果……畢竟數據結構只會是一個輔助而已。仔細想來,好像除了權值線段樹能夠維護\(\rm{DP}\)之外,沒做過什麽數據結構的好題,都是一些數據結構的裸題……大概這就是學傻了吧,只會專一的一門學科,或者說只會專精一種東西——還是十分蠢笨遲鈍地“專精”。
唉,大概檢驗一個人學沒學過數據結構,不是通過他會不會做類似於\(NOI2005\)維護數列那樣的毒瘤裸題,而是看他到底可不可以和其他的東西結合在一起。學習大抵也是同樣的道理,不可以把學的東西遷移到其他地方,照樣是白學吧。
誒,好像扯了什麽奇怪的東西……
回到正題,我們不考慮直接維護這個東西,而是通過維護區間內的最長連續\(0\)的個數,達到輔助查找區間的目的。那麽我們查找區間的時候,就直接**擇最左邊的區間優先,並\(check\)其是否有足夠的\(0\)。
對於查詢,我們先查詢左區間,再查詢中間(左區間的右邊與右區間的並集),最後查詢右區間。
#include <cstdio>
#include <iostream>
#define MAXN 200100
#define ls(x) x << 1
#define rs(x) x << 1 | 1
#define mid ((l + r) >> 1)
using namespace std ;
struct Tree{
int Sum, Len, Lsum, Rsum, tag ;
}T[MAXN << 1] ; int A, B, N, M, MArk, i, t ;
inline void push_down(int rt){
if (T[rt].tag == -1) return ;
else if (T[rt].tag == 0){
T[ls(rt)].tag = T[rs(rt)].tag = 0 ;
T[ls(rt)].Lsum = T[ls(rt)].Sum = T[ls(rt)].Rsum = 0 ;
T[rs(rt)].Lsum = T[rs(rt)].Sum = T[rs(rt)].Rsum = 0 ;
}
else{
T[ls(rt)].tag = T[rs(rt)].tag = 1 ;
T[ls(rt)].Lsum = T[ls(rt)].Sum = T[ls(rt)].Rsum = T[ls(rt)].Len ;
T[rs(rt)].Lsum = T[rs(rt)].Sum = T[rs(rt)].Rsum = T[rs(rt)].Len ;
}
T[rt].tag = -1 ;
}
inline void push_up(int rt){
if (T[ls(rt)].Sum == T[ls(rt)].Len)
T[rt].Lsum = T[ls(rt)].Len + T[rs(rt)].Lsum ;
else T[rt].Lsum = T[ls(rt)].Lsum ;
if (T[rs(rt)].Sum == T[rs(rt)].Len)
T[rt].Rsum = T[rs(rt)].Len + T[ls(rt)].Rsum ;
else T[rt].Rsum = T[rs(rt)].Rsum ;
T[rt].Sum = max(T[ls(rt)].Sum, T[rs(rt)].Sum),
T[rt].Sum = max(T[rt].Sum, T[ls(rt)].Rsum + T[rs(rt)].Lsum) ;
}
void build(int rt, int l, int r){
T[rt].tag = -1,
T[rt].Len = T[rt].Lsum =
T[rt].Rsum = T[rt].Sum = r - l + 1 ;
if (l == r){ return ; }
build(ls(rt), l, mid), build(rs(rt), mid + 1, r) ;
}
void update(int rt, int l, int r, int ul, int ur, int k){
if (ul <= l && ur >= r){
T[rt].tag = k ;
if (k == 0) T[rt].Lsum = T[rt].Rsum = T[rt].Sum = 0 ;
else T[rt].Lsum = T[rt].Rsum = T[rt].Sum = T[rt].Len ;
return ;
}
push_down(rt) ;
if (ul <= mid) update(ls(rt), l, mid, ul, ur, k) ;
if (ur > mid) update(rs(rt), mid + 1, r, ul, ur, k) ;
push_up(rt) ;
}
int query(int rt, int l, int r){
push_down(rt) ;
if (l == r) return l ;
if (T[ls(rt)].Sum >= A) return query(ls(rt), l, mid) ;
else if (T[ls(rt)].Rsum + T[rs(rt)].Lsum >= A) return mid - T[ls(rt)].Rsum + 1 ;
return query(rs(rt), mid + 1, r) ;
}
int main(){
cin >> N >> M ;
build(1, 1, N) ;
while(M --){
scanf("%d", &MArk) ;
if (MArk == 2) scanf("%d%d", &A, &B), update(1, 1, N, A, A + B - 1, 1) ;
else {
scanf("%d", &A) ;
if (T[1].Sum >= A)
printf("%d\n", t = query(1, 1, N)), update(1, 1, N, t, t + A - 1, 0) ;
else
putchar('0'), putchar('\n') ;
}
} return 0 ;
}
\(emmm\)這個題碼量其實不大,思維含量也不高,但是成功地把做數據結構題做傻了的我拉回了正途。
\(\rm{SCOI}\) 序列操作
\(Link\)
對於一個\(01\)序列,大體是這幾種操作:
- 區間清零
- 區間置為\(1\)
- 區間全部取非
- 區間查詢\(1\)的個數
- 區間查詢最長連續的\(1\)的長度
好的,這道題被我秒了,爽啊……不過秒是秒了,對拍調試法調了好久\(233\)。
其實對於\(1,2,4,5\)都好說,只是第\(3\)個操作,需要再另維護區間最長連續的\(0\)的長度,如果存在取非標記生效,就交換一下就行。
#include <cstdio>
#include <iostream>
#define MAX 200010
#define ls(x) x << 1
#define rs(x) x << 1 | 1
#define mid ((l + r) >> 1)
using namespace std ;
struct Tree{
int OS, OL, OR ;
int Sum, Lsum, Len, Rsum, S, tag, t ;
//tag = 1 -> 1,tag = 0 -> 0, tag = 2 -> xor
}T[MAX << 1] ; int N, M, MArk, L, R, base[MAX], i ;
inline void up(int rt){//
T[rt].S = T[ls(rt)].S + T[rs(rt)].S ;
//1
if (T[ls(rt)].S == T[ls(rt)].Len)
T[rt].Lsum = max(T[ls(rt)].Lsum, T[ls(rt)].Len + T[rs(rt)].Lsum) ;
else T[rt].Lsum = T[ls(rt)].Lsum ;
if (T[rs(rt)].S == T[rs(rt)].Len)
T[rt].Rsum = max(T[rs(rt)].Rsum, T[rs(rt)].Len + T[ls(rt)].Rsum) ;
else T[rt].Rsum = T[rs(rt)].Rsum ;
T[rt].Sum = max(T[ls(rt)].Rsum + T[rs(rt)].Lsum, max(T[ls(rt)].Sum, T[rs(rt)].Sum)) ;
//0
if (!T[ls(rt)].S)
T[rt].OL = max(T[ls(rt)].OL, T[ls(rt)].Len + T[rs(rt)].OL) ;
else T[rt].OL = T[ls(rt)].OL ;
if (!T[rs(rt)].S)
T[rt].OR = max(T[rs(rt)].OR, T[rs(rt)].Len + T[ls(rt)].OR) ;
else T[rt].OR = T[rs(rt)].OR ;
T[rt].OS = max(T[ls(rt)].OR + T[rs(rt)].OL, max(T[ls(rt)].OS, T[rs(rt)].OS)) ;
}
inline void down(int rt){//
if (T[rt].tag == -1) return ;
if (T[rt].t == 1){
T[ls(rt)].tag ^= 1, T[rs(rt)].tag ^= 1 ;
T[ls(rt)].S = T[ls(rt)].Len - T[ls(rt)].S ;
T[rs(rt)].S = T[rs(rt)].Len - T[rs(rt)].S ;
//l
T[ls(rt)].Sum ^= T[ls(rt)].OS ^= T[ls(rt)].Sum ^= T[ls(rt)].OS ;
T[ls(rt)].Lsum ^= T[ls(rt)].OL ^= T[ls(rt)].Lsum ^= T[ls(rt)].OL ;
T[ls(rt)].Rsum ^= T[ls(rt)].OR ^= T[ls(rt)].Rsum ^= T[ls(rt)].OR ;
//r
T[rs(rt)].Sum ^= T[rs(rt)].OS ^= T[rs(rt)].Sum ^= T[rs(rt)].OS ;
T[rs(rt)].Lsum ^= T[rs(rt)].OL ^= T[rs(rt)].Lsum ^= T[rs(rt)].OL ;
T[rs(rt)].Rsum ^= T[rs(rt)].OR ^= T[rs(rt)].Rsum ^= T[rs(rt)].OR ;
}
if (T[rt].tag == 0){
T[ls(rt)].tag = T[rs(rt)].tag = 0 ;
T[ls(rt)].OL = T[ls(rt)].OR = T[ls(rt)].OS = T[ls(rt)].Len ;
T[rs(rt)].OL = T[rs(rt)].OR = T[rs(rt)].OS = T[rs(rt)].Len ;
T[ls(rt)].Lsum = T[ls(rt)].Rsum = T[ls(rt)].Sum = T[ls(rt)].S = 0 ;
T[rs(rt)].Lsum = T[rs(rt)].Rsum = T[rs(rt)].Sum = T[rs(rt)].S = 0 ;
}
if (T[rt].tag == 1){
T[ls(rt)].tag = T[rs(rt)].tag = 1 ;
T[ls(rt)].OL = T[ls(rt)].OR = T[ls(rt)].OS = 0 ;
T[rs(rt)].OL = T[rs(rt)].OR = T[rs(rt)].OS = 0 ;
T[ls(rt)].Lsum = T[ls(rt)].Rsum = T[ls(rt)].Sum = T[ls(rt)].S = T[ls(rt)].Len ;
T[rs(rt)].Lsum = T[rs(rt)].Rsum = T[rs(rt)].Sum = T[rs(rt)].S = T[rs(rt)].Len ;
}
T[rt].tag = -1, T[rt].t = 0 ;
}
void _change(int rt, int l, int r, int k){//
if (L <= l && r <= R){
T[rt].tag = k ;
if (!k)
T[rt].OL = T[rt].OR = T[rt].OS = T[rt].Len,
T[rt].Lsum = T[rt].Rsum = T[rt].Sum = T[rt].S = 0 ;
else T[rt].OL = T[rt].OR = T[rt].OS = 0,
T[rt].Lsum = T[rt].Rsum = T[rt].Sum = T[rt].S = T[rt].Len ;
return ;
}
down(rt) ;
if (L <= mid) _change(ls(rt), l, mid, k) ;
if (R > mid) _change(rs(rt), mid + 1, r, k) ;
up(rt) ;
}
void _reverse(int rt, int l, int r){//
if (L <= l && r <= R){
T[rt].t = 1 ;
T[rt].Sum ^= T[rt].OS ^= T[rt].Sum ^= T[rt].OS ;
T[rt].Lsum ^= T[rt].OL ^= T[rt].Lsum ^= T[rt].OL ;
T[rt].Rsum ^= T[rt].OR ^= T[rt].Rsum ^= T[rt].OR ;
return ;
}
down(rt) ;
if (L <= mid) _reverse(ls(rt), l, mid) ;
if (R > mid) _reverse(rs(rt), mid + 1, r) ;
up(rt) ;
}
inline int Sum(int rt, int l, int r){//
if (L <= l && R >= r) return T[rt].S ;
down(rt) ; int res = 0 ;
if (L <= mid) res += Sum(ls(rt), l, mid) ;
if (R > mid) res += Sum(rs(rt), mid + 1, r) ;
return res ;
}
inline void build(int rt, int l, int r){//
T[rt].tag = -1 ;
T[rt].Len = r - l + 1 ;
if (l == r){
if (!base[l]) T[rt].OL = T[rt].OR = T[rt].OS = 1 ;
else T[rt].Sum = T[rt].Lsum = T[rt].Rsum = T[rt].S = 1 ;
return ;
}
build(ls(rt), l, mid), build(rs(rt), mid + 1, r), up(rt) ;
}
inline Tree query(int rt, int l, int r){
if (L <= l && R >= r) return T[rt] ;
Tree res, A, B ;
if (mid >= R) return query(ls(rt), l, mid) ;
if (mid < L) return query(rs(rt), mid + 1, r) ;
A = query(ls(rt), l, mid), B = query(rs(rt), mid + 1, r) ;
res.Lsum = max(A.Lsum, A.S + B.Lsum) ; res.Rsum = max(B.Rsum, B.S + A.Rsum) ;
res.Sum = max(max(A.Sum, B.Sum), A.Rsum + B.Lsum) ; res.S = A.S + B.S ;
return res ;
}
int main(){
cin >> N >> M ;
for (i = 1 ; i <= N ; ++ i) scanf("%d", &base[i]) ;
build(1, 1, N) ;
while (M --){
// cout << M << " " << "qwerweafasdfsdf" << endl ;
scanf("%d%d%d", &MArk, &L, &R),
++ L, ++ R ;
if (MArk == 0) _change(1, 1, N, 0) ;
else if (MArk == 1) _change(1, 1, N, 1) ;
else if (MArk == 2) _reverse(1, 1, N) ;
else if (MArk == 3) printf("%d\n", Sum(1, 1, N)) ;
else printf("%d", query(1, 1, N).Sum), putchar('\n') ;
// cout << " qwerweafasdfsdf " << endl ;
}
}
\(push\_up\)真長啊\(233\)
艹完這個題是真的爽啊~
\(Task3~\) 總結一下
其實這東西和\(DP\)是一樣的吧?你只需要確定你想要維護什麽(等價於確定狀態),然後明確父子區間如何向上維護(等價於狀態之間如何轉移)。
嗯,萬物相同。
野馬也,塵埃也,生物之以息向吹也。天之蒼蒼,其正色耶?其遠而無所至極耶?
不知為什麽,突然想到了這句話。
\(\mathscr{The~End}\)
淺談一類線段樹轉移的問題