NamomoCamp-线段树 部分题解


NamomoCamp2020-div2-day5-线段树 部分题解

Subsequence Count (hdu 6155)

Tag

dp, 矩阵,线段树

Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
f[i][0] 考虑前 i 位,以 0 结尾的本质不同子序列个数
f[i][1] 考虑前 i 位,以 1 结尾的本质不同子序列个数
s[i]==0 -> f[i][0]=f[i-1][0]+f[i-1][1]+1;
f[i][1]=f[i-1][1];
s[i]==1 -> f[i][1]=f[i-1][0]+f[i-1][1]+1;
f[i][0]=f[i-1][0];
转化为矩阵乘法
mat -> [f[i][0] f[i][1] 1]
初值 -> [0 0 1]

s[i]==0 -> [1 0 0]
[1 1 0]
[1 0 1]

s[i]==1 -> [1 1 0]
[0 1 0]
[0 1 1]
info = 转移矩阵乘积
tag = flip, flip 区间 = 每个单点的矩阵 swap 1,2行和1,2列 = 矩阵乘积swap 1,2行和1,2列 (横竖编号均变化 [1,2,3]->[2,1,3] )
info合并: 矩阵乘
tag合并: 异或
tag更新info: 矩阵交换
query得出矩阵乘mul, [0 0 1] * mul = [f[0] f[1] 1]
ans = f[0] + f[1]
Code
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
typedef pair<ll, ll> pll;

const int maxn = 100005;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;

struct mat {
#define N 3
ll w[N][N];

mat() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
w[i][j] = 0;
}
}
}
mat(int _w[][N]) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
w[i][j] = _w[i][j];
}
}
}

mat operator * (mat m) {
mat ret;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
ret.w[i][j] += w[i][k] * m.w[k][j] % mod;
ret.w[i][j] %= mod;
}
}
}
return ret;
}

void swapRow(int x, int y) {
for (int j = 0; j < N; j++) {
swap(w[x][j], w[y][j]);
}
}
void swapColumn(int x, int y) {
for (int i = 0; i < N; i++) {
swap(w[i][x], w[i][y]);
}
}
#undef N
};

int w[2][3][3] = {
{
{1, 0, 0},
{1, 1, 0},
{1, 0, 1}
},
{
{1, 1, 0},
{0, 1, 0},
{0, 1, 1}
}
};
int c[3][3] = {
{1, 0, 0},
{0, 1, 0},
{0, 0, 1}
};
char s[maxn];

struct Tag {
int rev;
Tag() {}
Tag(int _rev) {
rev = _rev;
}
void clear() {
rev = 0;
}
void mergeTag(Tag k) {
rev ^= k.rev;
}
} tag[maxn << 2];

struct Info {
mat m;
Info() {
m = mat(c);
}
Info(mat _m) {
m = _m;
}
void applyTag(Tag k) {
if (k.rev) {
m.swapRow(0, 1);
m.swapColumn(0, 1);
}
}
} info[maxn << 2];

Info mergeInfo(Info x, Info y) {
return Info(x.m * y.m);
}

void applyTag(int x, Tag k) {
tag[x].mergeTag(k);
info[x].applyTag(k);
}

void pushup(int x) {
info[x] = mergeInfo(info[x * 2], info[x * 2 + 1]);
}

void pushdown(int x) {
applyTag(x * 2, tag[x]);
applyTag(x * 2 + 1, tag[x]);
tag[x].clear();
}

void build(int x, int l, int r) {
if (l == r) {
info[x].m = mat(w[s[l] - '0']);
} else {
int mid = l + r >> 1;
build(x * 2, l, mid);
build(x * 2 + 1, mid + 1, r);
pushup(x);
}
tag[x].rev = 0;
}

void update(int x, int l, int r, int ql, int qr, Tag k) {
if (ql > r || qr < l) return;
if (ql <= l && r <= qr) {
applyTag(x, k);
return;
}
pushdown(x);
int mid = l + r >> 1;
update(x * 2, l, mid, ql, qr, k);
update(x * 2 + 1, mid + 1, r, ql, qr, k);
pushup(x);
}

Info query(int x, int l, int r, int ql, int qr) {
if (ql > r || qr < l) return Info();
if (ql <= l && r <= qr) {
return info[x];
}
pushdown(x);
int mid = l + r >> 1;
return mergeInfo(query(x * 2, l, mid, ql, qr), query(x * 2 + 1, mid + 1, r, ql, qr));
}

int main() {

int T;
scanf("%d", &T);
while (T--) {
int n, q;
scanf("%d%d", &n, &q);
scanf("%s", s + 1);
build(1, 1, n);
while (q--) {
int op, l, r;
scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
update(1, 1, n, l, r, Tag(1));
} else {
mat m;
m.w[0][2] = 1;
m = m * query(1, 1, n, l, r).m;
printf("%lld\n", (m.w[0][0] + m.w[0][1]) % mod);
}
}
}

return 0;
}