线段树是一种树状数据结构,它可以区间加减,区间乘除等一系列操作,用于处理那种可以合并状态的数据,在使用其 3 倍左右的空间的代价下使得其修改、查询、求区间和等等操作变得更加快捷。但与此同时,我们无法利用它处理类似于区间最长 01 序列此类问题,而且线段树代码冗长,其实很容易写错(也可能是因为我太菜了)。
我们将一组数据进行如下处理,每相邻的两个数据有一个父亲节点来记录其总的状态,然后再记录其相邻父节点的总的状态,以此类推,最终得到一个树状结构,我们从上到下依次编号 1-n,这棵树满足父节点 * 2 = 左节点,父节点 * 2+1 = 右节点,设每个父节点代表 l-r 区间的状态,则左区间为 l,(r+l)/2 , 右区间为 (r+l)/2+1,r。根据此性质我们可以对他们进行维护。
每当我们访问一个节点,我们保证此节点的值一定正确,并尽可能少的改变其子孙节点的值,让时间消耗尽可能的小,同时把 lazy 标记也就是本来应该加的数传递到下一节点。
第一颗树实现了区间加与查询,第二颗树实现了区间乘法,加法,判断其中的先后顺序,其实也大同小异。
第三颗树用于实现历史最大值这种操作,然而由于本人电脑跑不动 500mb 的程序,再加之修改起来有点麻烦,就写个大致正确的程序摆在这了。
如果要继续完善,那么需要记录次大值并对于 spread 函数进行修改,就这样吧,后面再来补。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std ;
typedef long long LL ;
const int maxn = 500005 ;
struct L {
LL val , add ;
} t[maxn] ;
LL n , m , a[maxn] ;

void build ( int p , int l , int r ) {
if ( l == r ) { t[p].val = a[l] ; return ; }
int mid = ( l + r ) >> 1 ;
build ( p << 1 , l , mid ) ;
build ( p << 1 | 1 , mid + 1 , r ) ;
t[p].val = t[p<<1].val + t[p<<1|1].val ;
return ;
}

void spread ( int p , int l , int r ) {
if ( t[p].add ) {
int mid = ( l + r ) >> 1 ;
t[p<<1].val = ( t[p<<1].val + t[p].add * ( mid - l + 1 ) ) , t[p<<1].add += t[p].add ;
t[p<<1|1].val = ( t[p<<1|1].val + t[p].add * ( r - mid ) ) , t[p<<1|1].add += t[p].add ;
t[p].add = 0 ;
}
}

void change ( int p , int l , int r , int x , int y , int z ) {
if ( x <= l && r <= y ) { t[p].val += z * ( r - l + 1 ) ; t[p].add += z ; return ; }
int mid = ( l + r ) >> 1 ; spread ( p , l , r ) ;
if ( x <= mid ) change ( p << 1 , l , mid , x , y , z ) ;
if ( y > mid ) change ( p << 1 | 1 , mid + 1 , r , x , y , z ) ;
t[p].val = t[p<<1].val + t[p<<1|1].val ;
}

LL ask ( int p , int l , int r , int x , int y ) {
if ( x <= l && r <= y ) { return t[p].val ; }
int mid = ( l + r ) >> 1 ; spread ( p , l , r ) ; LL ans = 0 ;
if ( x <= mid ) ans = ans + ask ( p << 1 , l , mid , x , y ) ;
if ( y > mid ) ans = ans + ask ( p << 1 | 1 , mid + 1 , r , x , y ) ;
return ans ;
}
int main ( ) {
scanf ( "%lld%lld" , & n , & m ) ;
for ( int i = 1 ; i <= n ; i ++ ) scanf ( "%lld" , & a[i] ) ;
build ( 1 , 1 , n ) ;
for ( int i = 1 ; i <= m ; i ++ ) {
int com , x , y ; scanf ( "%d%d%d" , & com , & x , & y ) ;
if ( com == 1 ) {
LL k ; scanf ( "%lld" , & k ) ;
change ( 1 , 1 , n , x , y , k ) ;
}
else printf ( "%lld\n" , ask ( 1 , 1 , n , x , y ) ) ;
}
return 0 ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std ;
const int N = 100003 ;
typedef long long ll ;
inline int read ( ) {
char ch = getchar ( ) ; int res = 0 ;
while ( ch > '9' || ch < '0' ) ch = getchar ( ) ;
while ( ch >= '0' && ch <= '9' ) res = res * 10 + ch - 48 , ch = getchar ( ) ;
return res ;
}

struct L {
ll mul , val , add ;
} t[N<<2] ;
int n , m , a[N] , mod ;

void build ( int p , int l , int r ) {
t[p].mul = 1 ;
if ( l == r ) { t[p].val = a[l] ; return ; }
int mid = ( l + r ) >> 1 ;
build ( p << 1 , l , mid ) ;
build ( p << 1 | 1 , mid + 1 , r ) ;
t[p].val = ( t[p<<1|1].val + t[p<<1].val ) % mod ;
}

void spread ( int p , int l , int r ) {
int mid = ( l + r ) >> 1 ;
t[p<<1].val = ( t[p<<1].val * t[p].mul + t[p].add * ( mid - l + 1 ) ) % mod ;
t[p<<1|1].val = ( t[p<<1|1].val * t[p].mul + t[p].add * ( r - mid ) ) % mod ;
t[p<<1].mul = ( t[p<<1].mul * t[p].mul ) % mod ;
t[p<<1|1].mul = ( t[p<<1|1].mul * t[p].mul ) % mod ;
t[p<<1].add = ( t[p<<1].add * t[p].mul + t[p].add ) % mod ;
t[p<<1|1].add = ( t[p<<1|1].add * t[p].mul + t[p].add ) % mod ;
t[p].mul = 1 ; t[p].add = 0 ;
}

void change2 ( int p , int l , int r , int x , int y , ll z ) {
if ( x <= l && r <= y ) {
t[p].mul = ( t[p].mul * z ) % mod ;
t[p].add = ( t[p].add * z ) % mod ;
t[p].val = ( t[p].val * z ) % mod ;
return ;
}
spread ( p , l , r ) ;
int mid = ( l + r ) >> 1 ;
if ( x <= mid ) change2 ( p << 1 , l , mid , x , y , z ) ;
if ( y > mid ) change2 ( p << 1 | 1 , mid + 1 , r , x , y , z ) ;
t[p].val = ( t[p<<1|1].val + t[p<<1].val ) % mod ;
}

void change1 ( int p , int l , int r , int x , int y , ll z ) {
if ( x <= l && r <= y ) {
t[p].add = ( t[p].add + z ) % mod ;
t[p].val = ( t[p].val + ( r - l + 1 ) * z ) % mod ;
return ;
}
spread ( p , l , r ) ;
int mid = ( l + r ) >> 1 ;
if ( x <= mid ) change1 ( p << 1 , l , mid , x , y , z ) ;
if ( y > mid ) change1 ( p << 1 | 1, mid + 1 , r , x , y , z ) ;
t[p].val = ( t[p<<1|1].val + t[p<<1].val ) % mod ;
}

ll aska ( int p , int l , int r , int x , int y ) {
if ( x <= l && r <= y ) return t[p].val ;
spread ( p , l , r ) ;
int mid = ( l + r ) >> 1 ;
ll ans = 0 ;
if ( x <= mid ) ans += aska ( p << 1 , l , mid , x , y ) ;
if ( mid < y ) ans += aska ( p << 1 | 1 , mid + 1 , r , x , y ) ;
ans %= mod ;
t[p].val = ( t[p<<1|1].val + t[p<<1].val ) % mod ;
return ans ;
}

int main ( ) {
n = read ( ) ; m = read ( ) ; mod = read ( ) ;
for ( int i = 1 ; i <= n ; i ++ ) scanf ( "%d" , & a[i] ) ;
build ( 1 , 1 , n ) ;
while ( m -- ) {
int command = read ( ) ; ll x = read ( ) , y = read ( ) ;
if ( command == 1 ) change2 ( 1 , 1 , n , x , y , read ( ) ) ;
if ( command == 2 ) change1 ( 1 , 1 , n , x , y , read ( ) ) ;
if ( command == 3 ) cout << aska ( 1 , 1 , n , x , y ) << endl ;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std ;
const int maxn = 2000006 ;
typedef long long LL ;
struct L {
LL val , maxa , maxb , add , mina ;
} t[maxn] ;
LL a[maxn>>2] ;

void build ( int p , int l , int r ) {
t[p].mina = 0x7fffffff ;
if ( l == r ) { t[p].maxa = t[p].maxb = t[p].val = a[l] ; return ; }
int mid = ( l + r ) >> 1 ;
build ( p << 1 , l , mid ) ;
build ( p << 1 | 1 , mid + 1 , r ) ;
t[p].maxa = max ( t[p<<1].maxa , t[p<<1|1].maxa ) ;
t[p].maxb = max ( t[p<<1].maxb , t[p<<1|1].maxb ) ;
t[p].val = t[p<<1].val + t[p<<1|1].val ;
}

void spread ( int p , int l , int r ) {
int mid = ( l + r ) >> 1 ;
//这里有一定的问题,需要判断变为最小的影响,需要分类讨论,其余的没有问题(大概)
t[p<<1].val = min ( t[p].mina , ( t[p<<1].val + t[p].add * ( mid - l + 1 ) ) ) ;
t[p<<1|1].val = min ( t[p].mina , ( t[p<<1|1].val + t[p].add * ( r - mid ) ) ) ;
//持续到这里
t[p<<1].maxa = max ( t[p<<1].maxa + t[p].add , t[p].mina == 0x7fffffff ? 0 : t[p].mina ) ;
t[p<<1|1].maxa = max ( t[p<<1|1].maxa + t[p].add , t[p].mina == 0x7fffffff ? 0 : t[p].mina ) ;
t[p<<1].maxb = max( t[p<<1].maxb , t[p<<1].maxa ) ;
t[p<<1|1].maxb = max ( t[p<<1|1].maxb , t[p<<1|1].maxa ) ;
t[p<<1].add += t[p].add ; t[p<<1|1].add += t[p].add ;
t[p<<1].mina = min ( t[p<<1].mina , t[p].mina ) ; t[p<<1|1].mina = min ( t[p<<1|1].mina , t[p].mina ) ;
t[p].mina = 0x7fffffff ; t[p].add = 0 ;
}

void change1 ( int p , int l , int r , int x , int y , LL z ) {
if ( x <= l && r <= y ) {
t[p].maxa += z ;
t[p].maxb = max ( t[p].maxb , t[p].maxa ) ;
t[p].val = ( t[p].val + z * ( r - l + 1 ) ) ;
t[p].add += z ;
}
int mid = ( l + r ) >> 1 ; spread ( p , l , r ) ;
if ( x <= mid ) change1 ( p << 1 , l , mid , x , y , z ) ;
if ( y > mid ) change1 ( p << 1 | 1 , mid + 1 , r , x , y , z ) ;
t[p].val = ( t[p<<1].val + t[p<<1|1].val ) ;
t[p].maxa = max ( t[p<<1].maxa , t[p<<1|1].maxa ) ;
t[p].maxb = max ( t[p<<1].maxb , t[p<<1|1].maxb ) ;
}

void change2 ( int p , int l , int r , int x , int y , LL z ) {
if ( x <= l && r <= y ) {
t[p].val = min ( t[p].val , z * ( r - l + 1 ) ) ;
t[p].maxa = min ( z , t[p].maxa ) ;
t[p].mina = z ;
t[p].maxb = max ( t[p].maxb , t[p].maxa ) ;
}
int mid = ( l + r ) >> 1 ; spread ( p , l , r ) ;
if ( x <= mid ) change2 ( p << 1 , l , mid , x , y , z ) ;
if ( y > mid ) change2 ( p << 1 | 1 , mid + 1 , r , x , y , z ) ;
t[p].val = ( t[p<<1].val + t[p<<1|1].val ) ;
t[p].maxa = max ( t[p<<1].maxa , t[p<<1|1].maxa ) ;
t[p].maxb = max ( t[p<<1].maxb , t[p<<1|1].maxb ) ;
}

LL ask1 ( int p , int l , int r , int x , int y ) {
if ( x <= l && r <= y ) { return t[p].val ; }
int mid = ( l + r ) >> 1 ; LL ans = 0 ; spread ( p , l , r ) ;
if ( x <= mid ) ans += ask1 ( p << 1 , l , mid , x , y ) ;
if ( y > mid ) ans += ask1 ( p << 1 | 1 , mid + 1 , r , x , y ) ;
return ans ;
}

LL ask2 ( int p , int l , int r , int x , int y ) {
if ( x <= l && r <= y ) { return t[p].maxa ; }
int mid = ( l + r ) >> 1 ; LL ans = 0x7fffffff ; spread ( p , l , r ) ;
if ( x <= mid ) ans = min ( ans , ask2 ( p << 1 , l , mid , x , y ) ) ;
if ( y > mid ) ans = min ( ans , ask2 ( p << 1 | 1 , mid + 1 , r , x , y ) ) ;
return ans ;
}

LL ask3 ( int p , int l , int r , int x , int y ) {
if ( x <= l && r <= y ) { return t[p].maxb ; }
int mid = ( l + r ) >> 1 ; LL ans = 0x7fffffff ; spread ( p , l , r ) ;
if ( x <= mid ) ans = min ( ans , ask3 ( p << 1 , l , mid , x , y ) ) ;
if ( y > mid ) ans = min ( ans , ask3 ( p << 1 | 1 , mid + 1 , r , x , y ) ) ;
return ans ;
}

int main ( ) {
int n , m ; scanf ( "%d%d" , & n , & m ) ;
for ( int i = 1 ; i <= n ; i ++ ) scanf ( "%lld" , & a[i] ) ;
build ( 1 , 1 , n ) ;
while ( m -- ) {
int op ; scanf ( "%d" , & op ) ;
if ( op == 1 ) {
int l , r ; LL k ; scanf ( "%d%d%lld" , & l , & r , & k ) ;
change1 ( 1 , 1 , n , l , r , k ) ;
}
else if ( op == 2 ) {
int l , r ; LL k ; scanf ( "%d%d%lld" , & l , & r , & k ) ;
change2 ( 1 , 1 , n , l , r , k ) ;
}
else if ( op == 3 ) {
int l , r ; scanf ( "%d%d" , & l , & r ) ;
printf ( "%lld" , ask1 ( 1 , 1 , n , l , r ) ) ;
}
else if ( op == 4 ) {
int l , r ; scanf ( "%d%d" , & l , & r ) ;
printf ( "%lld" , ask2 ( 1 , 1 , n , l , r ) ) ;
}
else {
int l , r ; scanf ( "%d%d" , & l , & r ) ;
printf ( "%lld" , ask3 ( 1 , 1 , n , l , r ) ) ;
}
}
return 0 ;
}

更新于 阅读次数