本节内容介绍了一些嵌套的数据结构
以及常用的算法思想
包括离线分治,点分治,分块数据结构等等

分块

POJ3468
POJ3468-02

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

const int maxn = 100000 + 5;
int n, m;
llong a[maxn];
int t;

int pos[maxn];
llong add[maxn], sum[maxn];
// add[i] is tot segment[i] is added d

void init() {
Set(pos, 0);
Set(add, 0);
Set(sum, 0);
}

class Seg {
public:
int l, r;
} seg[maxn];

inline void cal() {
t = sqrt(n);
_rep(i, 1, t) {
seg[i].l = (i - 1) * sqrt(n) + 1;
seg[i].r = i * sqrt(n);
}
if(seg[t].r < n) {
t++;
seg[t].l = seg[t - 1].r + 1;
seg[t].r = n;
}

_rep(i, 1, t) {
_rep(k, seg[i].l, seg[i].r) {
pos[k] = i;
sum[i] += a[k];
}
}
}

void change(int l, int r, llong d) {
int p = pos[l], q = pos[r];
if(p == q) {
_rep(i, l, r) a[i] += d;
sum[p] += d * (r - l + 1);
}
else {
_rep(i, p + 1, q - 1) add[i] += d;

_rep(i, l, seg[p].r) a[i] += d;
sum[p] += d * (seg[p].r - l + 1);

_rep(i, seg[q].l, r) a[i] += d;
sum[q] += d * (r - seg[q].l + 1);
}
}

llong ask(int l, int r) {
int p = pos[l], q = pos[r];
llong ans = 0;

if(p == q) {
_rep(i, l, r) ans += a[i];
ans += add[p] * (r - l + 1);
}
else {
_rep(i, p + 1, q - 1) {
ans += sum[i] + add[i] * (seg[i].r - seg[i].l + 1);
}

_rep(i, l, seg[p].r) ans += a[i];
ans += add[p] * (seg[p].r - l + 1);

_rep(i, seg[q].l, r) ans += a[i];
ans += add[q] * (r - seg[q].l + 1);
}
return ans;
}


int main() {
freopen("input.txt", "r", stdin);
init();
cin >> n >> m;
_rep(i, 1, n) scanf("%lld", &a[i]);

// init calculate
cal();
while (m--) {
char op[3];
int l, r, d;

scanf("%s", op);
scanf("%d%d", &l, &r);

if(op[0] == 'C') {
scanf("%d", &d);
change(l, r, d);
}
else printf("%lld\n", ask(l, r));
}
}

分块解决区间众数

BZOJ2724
BZOJ2724

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

const int maxn = 40000 + 5;
const int T = 800 + 5;
int f[T][T];
int n, m, t;
int a[maxn], b[maxn];
int ct[maxn];
vector<int> show[maxn];

map<int, int> loc;

class Seg {
public:
int l, r;
};

Seg seg[maxn];
int pos[maxn];

void init() {
Set(pos, 0);
Set(f, 0);
_for(i, 0, maxn) show[i].clear();
Set(ct, 0);

loc.clear();
}

void discrete() {
sort(b + 1, b + 1 + n);
int tot = unique(b + 1, b + 1 + n) - b - 1;

_rep(i, 1, n) {
a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
show[a[i]].push_back(i);
}

}



void split(const int len) {
_rep(i, 1, t) {
seg[i].l = (i - 1) * len + 1;
seg[i].r = i * len;
}
if(seg[t].r < n) {
t++;
seg[t].l = seg[t - 1].r + 1;
seg[t].r = n;
}

_rep(i, 1, n) {
_rep(j, seg[i].l, seg[i].r) pos[j] = i;
}
}

inline void cal() {
_rep(i, 1, t) {
int ans = 0, cnt = 0;
Set(ct, 0);

_rep(j, seg[i].l, n) {
ct[a[j]]++;
if(cnt < ct[a[j]] || (cnt == ct[a[j]] && a[j] < ans)) {
cnt = ct[a[j]];
ans = a[j];
}

f[i][pos[j]] = ans;
}
}
}

int count(int x, int l, int r) {
return upper_bound(show[x].begin(), show[x].end(), r) - lower_bound(show[x].begin(), show[x].end(), l);
}

void update(int x, int l, int r, int &ans, int &cnt) {
int c = count(x, l, r);
if(c > cnt || (c == cnt && x < ans)) {
cnt = c;
ans = x;
}
}

int ask(int l, int r) {
int p = pos[l], q = pos[r];
int ans = 0, cnt = 0;
if(p == q) {
_rep(i, l, r) update(a[i], l, r, ans, cnt);
return b[ans];
}

int x = 0, y = 0;
if(p + 1 <= q - 1) {
x = p + 1;
y = q - 1;
}

_rep(i, l, seg[p].r) update(a[i], l, r, ans, cnt);
_rep(i, seg[q].l, r) update(a[i], l, r, ans, cnt);
if(f[x][y]) update(f[x][y], l, r, ans, cnt);

//debug(ans);
return b[ans];
}

int main() {
freopen("input.txt", "r", stdin);
init();
cin >> n >> m;
_rep(i, 1, n) scanf("%d", &a[i]);
Cpy(b, a);


// == discrete ==
discrete();
// == discrete finished ==



// == part ==
t = sqrt(n * log(n) / log(2));
int len = t ? n / t : n;

// == split ==
split(len);
// == split finished ==

// == calculate f() ==
cal();
// == f() finished==

// == main algorithm ==
int res = 0;
while (m--) {
int l, r;
scanf("%d%d", &l, &r);

l = (l + res - 1) % n + 1;
r = (r + res - 1) % n + 1;
//debug(l), debug(r);

if(l > r) swap(l, r);
res = ask(l, r);
printf("%d\n", res);
}

}

多变量分块

Acwing250
CH46A
acwing250

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

const int maxn = 250000 + 5;
int n, t;

class Magnet {
public:
int x, y, m, p, r;
};

Magnet P[maxn];
queue<Magnet> que;
int vis[maxn];
Magnet st;
int cnt = 0;

void init() {
Set(vis, 0);
cnt = 0;
}

bool cmp(Magnet lhs, Magnet rhs) {
return lhs.m < rhs.m;
}

bool cmp2(Magnet a, Magnet b) {
return (llong)(a.x - st.x) * (a.x - st.x) + (llong)(a.y - st.y) * (a.y - st.y) < (llong)(b.x - st.x) * (b.x - st.x) + (llong)(b.y - st.y) * (b.y - st.y);
}

bool attr(Magnet a, Magnet b) {
return (llong)(b.x - st.x) * (b.x - st.x) + (llong)(b.y - st.y) * (b.y - st.y) <= (llong)a.r * a.r;
}


class Seg {
public:
int l, r, M;
};

Seg seg[maxn];

void cal() {
sort(P + 1, P + 1 + n, cmp);

t = sqrt(n);
_rep(i, 1, t) {
seg[i].l = (i - 1) * t + 1;
seg[i].r = i * t;
seg[i].M = P[seg[i].r].m;

sort(P + seg[i].l, P + seg[i].r + 1, cmp2);
}

if(seg[t].r < n) {
t++;
seg[t].l = seg[t - 1].r + 1;
seg[t].r = n;
seg[t].M = P[n].m;

sort(P + seg[t].l, P + seg[t].r + 1, cmp2);
}
}

void bfs() {
que.push(st);
cnt = 1;

while (!que.empty()) {
Magnet cur = que.front();
que.pop();

int k = 0;
_rep(i, 1, t) {
if(seg[i].M <= cur.p) k = i;
else break;
}

_rep(i, 1, k) {
while (seg[i].l <= seg[i].r && attr(cur, P[seg[i].l])) {
// check attr, and push
if(!vis[seg[i].l]) {
vis[seg[i].l] = 1;
que.push(P[seg[i].l]);
cnt++;
}

seg[i].l++;
}
}

if(k != t) {
k++;
_rep(i, seg[k].l, seg[k].r) {
if(!vis[i] && P[i].m <= cur.p && attr(cur, P[i])) {
vis[i] = 1;
que.push(P[i]);
cnt++;
}
}
}
}

cout << cnt - 1 << endl;
}

int main() {
freopen("input.txt", "r", stdin);
init();
cin >> st.x >> st.y >> st.p >> st.r >> n;
_rep(i, 1, n) scanf("%d %d %d %d %d", &P[i].x, &P[i].y, &P[i].m, &P[i].p, &P[i].r);

// == split into block
cal();
// == split into block finished

// == bfs
bfs();
// == bfs finished
}

莫队算法

莫队算法模版

排序和分块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bool cmp(const Qry& a, const Qry& b) {
if(belong[a.l] ^ belong[b.l]) return belong[a.l] < belong[b.l];
if(belong[a.l] & 1) return a.r < b.r;
return a.r > b.r;
}

void block() {
sz = sqrt(1.0 * n);
t = n / sz;

_rep(i, 1, t) _rep(k, (i - 1) * sz + 1, i * sz) {
belong[k] = i;
}
if(t * sz < n) {
t++;
_rep(k, (t - 1) * sz + 1, n) belong[k] = t;
}
}

Mo’s Algorithm主过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
inline void add(int x, int& ans) {
if(++num[x] == 1) ans++;
}

inline void del(int x, int& ans) {
if(--num[x] == 0) ans--;
}

void solve() {
sort(qry + 1, qry + 1 + m, cmp);
Set(num, 0);
tans = 0;

int l = 1, r = 0;

_rep(i, 1, m) {
while (l < qry[i].l) del(A[l++], tans);
while (l > qry[i].l) add(A[--l], tans);
while (r < qry[i].r) add(A[++r], tans);
while (r > qry[i].r) del(A[r--], tans);

ANS[qry[i].id] = tans;
}
}

离线莫队(不带修改)

有名的袜子
BZOJ2038

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

const int maxn = 50000 + 10;
int n, m, t;
int color[maxn];
llong Ans[maxn][2];

class Q {
public:
int l, r, id;
};

Q qry[maxn];

class Blk {
public:
int L, R;
};

Blk blk[maxn];

bool cmp1(const Q& lhs, const Q& rhs) {
return lhs.l < rhs.l || (lhs.l == rhs.l && lhs.r < rhs.r);
}

bool cmp2(const Q& lhs, const Q& rhs) {
return lhs.r < rhs.r;
}

void block() {
sort(qry + 1, qry + 1 + m, cmp1);
t = sqrt(m);

_rep(i, 1, t) {
blk[i].L = (i - 1) * t + 1;
blk[i].R = i * t;
}
if(blk[t].R < n) {
t++;
blk[t].L = blk[t - 1].R + 1;
blk[t].R = n;
}
}


// == then solve the problem ==

inline llong gcd(llong a, llong b) {
return b ? gcd(b, a % b) : a;
}

int num[maxn];
llong tans = 0;
// tans used for temp ans in the block

void initBlk(int i) {
tans = 0;
Set(num, 0);

sort(qry + blk[i].L, qry + blk[i].R + 1, cmp2);
}

void maintain(int x, int d, llong& tans) {
tans -= num[x] * (num[x] - 1);
num[x] += d;
tans += num[x] * (num[x] - 1);
}

void solve() {
_rep(i, 1, t) {
initBlk(i);

// brute force for the first elem
int l = qry[blk[i].L].l, r = qry[blk[i].L].r;
_rep(k, l, r) maintain(color[k], 1, tans);
int qid = blk[i].L;
Ans[qry[qid].id][0] = tans;
Ans[qry[qid].id][1] = (llong)(r - l + 1) * (r - l);
int g = gcd(Ans[qry[qid].id][0], Ans[qry[qid].id][1]);
if(g == 0) Ans[qry[qid].id][1] = 1;
else {
Ans[qry[qid].id][0] /= g;
Ans[qry[qid].id][1] /= g;
}

// then get [blk[i].L + 1, blk[i].R] by recursion
_rep(k, blk[i].L + 1, blk[i].R) {
// now qid = k;
while (r < qry[k].r) maintain(color[++r], 1, tans);
while (r > qry[k].r) maintain(color[r--], -1, tans);
while (l < qry[k].l) maintain(color[l++], -1, tans);
while (l > qry[k].l) maintain(color[--l], 1, tans);

if(qry[k].l == qry[k].r) {
Ans[qry[k].id][0] = 0;
Ans[qry[k].id][1] = 1;
}
else {
Ans[qry[k].id][0] = tans;
Ans[qry[k].id][1] = (llong)(qry[k].r - qry[k].l + 1) * (qry[k].r - qry[k].l);

int g = gcd(Ans[qry[k].id][0], Ans[qry[k].id][1]);
if(!g) Ans[qry[k].id][1] = 1;
else {
Ans[qry[k].id][0] /= g;
Ans[qry[k].id][1] /= g;
}
}
}
}
}

// === solve finished ==

int main() {
freopen("input.txt", "r", stdin);

Set(Ans, 0);
cin >> n >> m;
_rep(i, 1, n) scanf("%d", &color[i]);
_rep(i, 1, m) {
scanf("%d%d", &qry[i].l, &qry[i].r);
qry[i].id = i;
}

// == input finished==

// === then split query into block ==
block();
// === blocked ===


// == then query in each blocked sorted by cmp2
solve();
// === sorted finished

_rep(i, 1, m) {
printf("%lld/%lld\n", Ans[i][0], Ans[i][1]);
}
}

不带修改的离线莫队,有时候需要一下两个函数
往往在查询固定区间[l,r][l, r]中有多少个不同元素的时候,需要用到

1
2
3
4
5
6
7
8
9
10
int num[maxn];
llong cnt;

inline void add(int p, int& ans) {
if(++num[A[p]] == 1) ans++;
}

inline void rmv(int p, int& ans) {
if(--num[A[p]] == 0) ans--;
}

带修改莫队

BZOJ2120
BZOJ2120-01
BZOJ2120-02

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

const int maxn = 1000000 + 5;
int n, m, t, sz;
int CNT[maxn];
int clr[maxn];
int cntq = 0, cntc = 0;
int ANS[maxn];

void init() {
cntq = cntc = 0;
}

class Query {
public:
int l, r, id, time;
};

Query qry[maxn];

inline void add(int x, int& ans) {
if(++CNT[x] == 1) ans++;
}

inline void del(int x, int& ans) {
if(--CNT[x] == 0) ans--;
}


// == init block ==
int tans = 0;
void initBlk() {
tans = 0;
}
// == init block finished ==

class Modify {
public:
int pos, curC;
void apply(int curL, int curR) {
if(curL <= pos && pos <= curR) {
int oldC = clr[pos];
del(oldC, tans);
add(curC, tans);
}
swap(curC, clr[pos]);
}
};
Modify mdfy[maxn];

// === block() by n ===
int belong[maxn];
void block() {
Set(belong, 0);
sz = pow(n, 2.0 / 3.0);
t = n / sz;

_rep(i, 1, t) {
_rep(k, (i - 1) * sz + 1, i * sz) belong[k] = i;
}
if(t * sz < n) {
t++;
_rep(k, (t - 1) * sz + 1, n) belong[k] = t;
}
// debug(t);
}

// == solve() ==
bool cmp(const Query& a, const Query& b) {
if(belong[a.l] ^ belong[b.l]) return belong[a.l] < belong[b.l];
if(belong[a.r] ^ belong[b.r]) return belong[a.r] < belong[b.r];
return a.time < b.time;
}

void solve() {
sort(qry + 1, qry + 1 + cntq, cmp);
initBlk();
assert(tans == 0);

// get started ptime and [l, r]
int ptime = 0, l = 0, r = 0;

// then expand to other query by recursion
_rep(i, 1, cntq) {
int ql = qry[i].l, qr = qry[i].r, qt = qry[i].time;
while (l < ql) del(clr[l++], tans);
while (l > ql) add(clr[--l], tans);
while (r < qr) add(clr[++r], tans);
while (r > qr) del(clr[r--], tans);

while (ptime < qt) mdfy[++ptime].apply(l, r);
while (ptime > qt) mdfy[ptime--].apply(l, r);

ANS[qry[i].id] = tans;
//debug(clr[1]);
}

}

// == solve fnished ==

// === block() finished ===

int main() {
freopen("input.txt", "r", stdin);
init();

// == input ==
scanf("%d%d", &n, &m);
_rep(i, 1, n) {
scanf("%d", &clr[i]);
}

assert(cntq == 0 && cntc == 0);
_rep(i, 1, m) {
char op[2];
scanf("%s", op);
if(op[0] == 'Q') {
Query& curq = qry[++cntq];
scanf("%d%d", &curq.l, &curq.r);
curq.id = cntq;
curq.time = cntc;

//debug(curq.time);
}
else {
Modify& md = mdfy[++cntc];
scanf("%d%d", &md.pos, &md.curC);
// mdfy[] as a tag, we not really change here
}
}
// == input finished ==

// == block ==
block();
// == block finished ==

solve();
_rep(i, 1, cntq) printf("%d\n", ANS[i]);
}

区间众数莫队处理

Acwing249
Acwing249

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

const int maxn = 40000 + 10;
const int maxt = 35 + 5;

class Mode {
public:
int CNT, pos;
void clear() {
CNT = pos = 0;
}
};
Mode f[maxt][maxt], cur;

int belong[maxn], c[maxt][maxt][maxn];

void init() {
Set(belong, 0);
Set(c, 0);
}

int a[maxn], buf[maxn];
int n, m, tot, t, sz;

void discrete() {
Cpy(buf, a);
sort(buf + 1, buf + 1 + n);
tot = unique(buf + 1, buf + 1 + n) - buf - 1;
_rep(i, 1, n) {
a[i] = lower_bound(buf + 1, buf + 1 + tot, a[i]) - buf;
}
}

// == block ==
class Blk {
public:
int L, R;
};
Blk blk[maxn];

void block() {
t = pow((double)n, 1.0 / 3.0);
sz = t ? n / t : n;

_rep(i, 1, t) {
blk[i].L = (i - 1) * sz + 1;
blk[i].R = i * sz;
}
if(blk[t].R < n) {
t++;
blk[t].L = blk[t - 1].R + 1;
blk[t].R = n;
}

_rep(i, 1, t) _rep(k, blk[i].L, blk[i].R) {
belong[k] = i;
}
}

// == blocked finished ==

// == init seg ==
void initseg() {
cur.clear();
_for(i, 0, maxt) _for(j, 0, maxt) f[i][j].clear();

_rep(i, 1, t) _rep(j, i, t) {
_rep(k, blk[i].L, blk[j].R) {
++c[i][j][a[k]];
}

_rep(x, 1, tot) {
if(f[i][j].CNT < c[i][j][x]) {
f[i][j].CNT = c[i][j][x];
f[i][j].pos = x;
}
}
}
}

// == init seg finished ==
inline void maintain(int x, int y, int val) {
++c[x][y][val];
if(c[x][y][val] > cur.CNT || (c[x][y][val] == cur.CNT && val < cur.pos)) {
cur.CNT = c[x][y][val];
cur.pos = val;
}
}
// == query ==
int query(int l, int r) {
int p = belong[l], q = belong[r];
int x = 0, y = 0;
if(p + 1 <= q - 1) {
x = p + 1; y = q - 1;
}

cur = f[x][y];

if(p == q) {
// at the same block
_rep(i, l, r) maintain(x, y, a[i]);
_rep(i, l, r) --c[x][y][a[i]];
}
else {
_rep(i, l, blk[p].R) maintain(x, y, a[i]);
_rep(i, blk[q].L, r) maintain(x, y, a[i]);
_rep(i, l, blk[p].R) --c[x][y][a[i]];
_rep(i, blk[q].L, r) --c[x][y][a[i]];
}

return buf[cur.pos];
}
// == query finished ==

int main() {
freopen("input.txt", "r", stdin);
init();

// == input ==
cin >> n >> m;
_rep(i, 1, n) scanf("%d", &a[i]);
// == input finished ==

// == discrete ==
discrete();
// == discrete finished ==


// == block ==
block();
// == block finished ==

// == then init Segment ==
initseg();
// == init segment finished ==

// == then solve() ==

int x = 0;
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
l = (l + x - 1) % n + 1;
r = (r + x - 1) % n + 1;
if(l > r) swap(l, r);

x = query(l, r);
printf("%d\n", x);
}
}