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
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
struct Query {
int L, R, idx;
int block;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
if (!(cin >> N)) return 0;
vector<int> A(N + 1);
for (int i = 1; i <= N; ++i) cin >> A[i];
// Prefix sums S[0..N]
vector<int> pref(N + 1, 0);
for (int i = 1; i <= N; ++i) pref[i] = pref[i - 1] + A[i];
// Coordinate compression of prefix sums
vector<int> all = pref;
sort(all.begin(), all.end());
all.erase(unique(all.begin(), all.end()), all.end());
int K = (int)all.size();
vector<int> idOfIndex(N + 1);
for (int i = 0; i <= N; ++i) {
idOfIndex[i] = int(lower_bound(all.begin(), all.end(), pref[i]) - all.begin());
}
int M; cin >> M;
vector<Query> qs(M);
int blockSize = max(1, int(sqrt(N + 1)));
for (int qi = 0; qi < M; ++qi) {
int i, j; cin >> i >> j;
// Work on prefix indices [i-1, j]
qs[qi] = {i - 1, j, qi, (i - 1) / blockSize};
}
sort(qs.begin(), qs.end(), [&](const Query &a, const Query &b) {
if (a.block != b.block) return a.block < b.block;
if (a.block & 1) return a.R > b.R;
return a.R < b.R;
});
// Data structures for Mo
vector<deque<int>> positions(K); // positions of each compressed prefix value inside current window
int lenBlock = max(1, int(sqrt(N + 1)));
vector<int> cntLen(N + 1, 0); // how many values currently have span exactly d
vector<int> bucket((N + lenBlock) / lenBlock + 2, 0); // number of d in block with cntLen[d] > 0
auto incLen = [&](int d) {
if (d < 0) return;
if (++cntLen[d] == 1) bucket[d / lenBlock]++;
};
auto decLen = [&](int d) {
if (d < 0) return;
if (--cntLen[d] == 0) bucket[d / lenBlock]--;
};
auto spanOf = [&](const deque<int> &dq) -> int {
if ((int)dq.size() < 2) return 0;
return dq.back() - dq.front();
};
auto getMaxLen = [&]() -> int {
for (int b = (int)bucket.size() - 1; b >= 0; --b) {
if (bucket[b] == 0) continue;
int start = min(N, (b + 1) * lenBlock - 1);
int base = b * lenBlock;
for (int d = start; d >= base; --d) {
if (cntLen[d] > 0) return d;
}
}
return 0;
};
\tint curL = 0, curR = -1;
vector<int> ans(M, 0);
auto addLeft = [&](int idx) {
int id = idOfIndex[idx];
int oldSpan = positions[id].empty() ? -1 : spanOf(positions[id]);
positions[id].push_front(idx);
int newSpan = spanOf(positions[id]);
if (oldSpan != -1) decLen(oldSpan);
incLen(newSpan);
};
auto addRight = [&](int idx) {
int id = idOfIndex[idx];
int oldSpan = positions[id].empty() ? -1 : spanOf(positions[id]);
positions[id].push_back(idx);
int newSpan = spanOf(positions[id]);
if (oldSpan != -1) decLen(oldSpan);
incLen(newSpan);
};
auto removeLeft = [&](int idx) {
int id = idOfIndex[idx];
int oldSpan = spanOf(positions[id]); // must be present
if (!positions[id].empty() && positions[id].front() == idx) positions[id].pop_front();
int newSpan = positions[id].empty() ? -1 : spanOf(positions[id]);
decLen(oldSpan);
if (newSpan != -1) incLen(newSpan);
};
auto removeRight = [&](int idx) {
int id = idOfIndex[idx];
int oldSpan = spanOf(positions[id]);
if (!positions[id].empty() && positions[id].back() == idx) positions[id].pop_back();
int newSpan = positions[id].empty() ? -1 : spanOf(positions[id]);
decLen(oldSpan);
if (newSpan != -1) incLen(newSpan);
};
for (const auto &q : qs) {
while (curL > q.L) addLeft(--curL);
while (curR < q.R) addRight(++curR);
while (curL < q.L) removeLeft(curL++);
while (curR > q.R) removeRight(curR--);
ans[q.idx] = getMaxLen();
}
for (int i = 0; i < M; ++i) {
cout << ans[i] << '\n';
}
return 0;
}
|