Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Forget the updates for a second. For one fixed array, two adjacent windows of length , starting at and , have the same multiset exactly when . Only one element leaves, one enters. That is the first crack in the wall.
If the same value appears at positions , then is always achievable: compare windows and . So is at least the maximum distance between two equal values.
The reverse direction is the part people usually miss. If two length- windows have equal multisets, cancel their overlap and look at the leftmost uncanceled element. It must reappear on the right at distance at least . Therefore no valid can exceed the maximum equal-value distance.
So is just . For each value with this maximum span , the position is a good start, meaning window equals window for length .
For the maximum length , any equal pair of windows must be connected by a chain of adjacent equal windows. So if the good starts for length form consecutive runs, a run of starts contributes triples. Maintain first/last occurrence per value, a multiset of spans, and per-span consecutive runs under point updates.
Core Observation
Let be the multiset of the length- window starting at .
First look at adjacent windows:
and differ only by removing and adding . Therefore
iff .
That means every pair of equal values at positions immediately gives a valid tuple with : compare and . So the answer's length is at least the largest distance between two equal values.
Now prove it cannot be bigger. Suppose two length- windows starting at have the same multiset. If , then must appear inside the second window, more than positions to the right. Otherwise, cancel the overlap of the two windows. The remaining left piece is , and the remaining right piece is ; these two pieces have the same multiset. The element must appear in the right piece, at position at least .
Either way, a valid length forces some equal pair of values at distance at least . So:
.
If no value appears twice, the set is empty and the answer is . No drama, just dead.
Counting Optimal Tuples
Let .
A position is called good if . Then the length- windows starting at and are equal.
Because is the maximum possible equal-value distance, if , then must be the first occurrence of that value and must be its last occurrence. So good starts are exactly:
for all values with .
Now comes the sneaky bit. For maximum length , if two windows and are equal, then all adjacent steps between them must also be equal:
.
Why? If , then the first element would need an equal copy farther than , impossible. Otherwise, after canceling overlap, match the left leftover positions to the right leftover positions. The first leftover position can only match , because matching anything farther would create an equal-value distance greater than . Remove that pair and repeat. Induction forces for every from to .
So an optimal tuple is exactly a nonempty consecutive block of good starts: .
If a maximal run of good starts has length , it contributes
valid tuples. Therefore is the sum of over all consecutive runs of good starts for length .
Dynamic Maintenance
For every value , keep an ordered set of its positions.
If appears at least twice, it contributes:
The global multiset tells us the current from its largest element.
For each possible length , maintain these candidate starts grouped into maximal consecutive intervals. Also maintain ways[d], the sum of over those intervals.
Tiny but important caveat: for non-maximum , this bucket is not necessarily the real answer for length . That is fine. We only ever read the bucket for the current maximum span , and for that length the candidates are exactly the good starts. Trying to maintain every length perfectly would be self-inflicted pain. Classic Codeforces tax, avoided.
When inserting a start position into bucket :
ways[d] by removing old interval contributions and adding the merged one.Deletion is the reverse: remove the interval containing , then split into up to two intervals.
A point update affects only two values: the old value and . Remove their old contributions, change the position sets, then insert their new contributions.
Finally:
0 0;K ways[K].Each update does a constant number of ordered-set operations, so the total complexity is $O((n+q)\log n)`.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll intervalWays(int l, int r) {
ll len = r - l + 1;
return len * (len + 1) / 2;
}
void solve() {
int n, q;
cin >> n >> q;
vector<int> a(n + 1);
vector<set<int>> pos(n + 1);
vector<set<pair<int, int>>> runs(n + 1);
vector<ll> ways(n + 1, 0);
multiset<int> spans;
auto addPoint = [&](int d, int p) {
int l = p, r = p;
auto it = runs[d].lower_bound({p + 1, -1});
if (it != runs[d].begin()) {
auto prv = prev(it);
if (prv->second + 1 == p) {
l = prv->first;
ways[d] -= intervalWays(prv->first, prv->second);
runs[d].erase(prv);
}
}
it = runs[d].lower_bound({p + 1, -1});
if (it != runs[d].end() && it->first == p + 1) {
r = it->second;
ways[d] -= intervalWays(it->first, it->second);
runs[d].erase(it);
}
runs[d].insert({l, r});
ways[d] += intervalWays(l, r);
};
auto removePoint = [&](int d, int p) {
auto it = prev(runs[d].upper_bound({p, n + 1}));
int l = it->first, r = it->second;
ways[d] -= intervalWays(l, r);
runs[d].erase(it);
if (l <= p - 1) {
runs[d].insert({l, p - 1});
ways[d] += intervalWays(l, p - 1);
}
if (p + 1 <= r) {
runs[d].insert({p + 1, r});
ways[d] += intervalWays(p + 1, r);
}
};
auto addValue = [&](int v) {
if ((int)pos[v].size() < 2) return;
int l = *pos[v].begin();
int r = *pos[v].rbegin();
int d = r - l;
spans.insert(d);
addPoint(d, l);
};
auto removeValue = [&](int v) {
if ((int)pos[v].size() < 2) return;
int l = *pos[v].begin();
int r = *pos[v].rbegin();
int d = r - l;
spans.erase(spans.find(d));
removePoint(d, l);
};
for (int i = 1; i <= n; i++) {
cin >> a[i];
pos[a[i]].insert(i);
}
for (int v = 1; v <= n; v++) addValue(v);
while (q--) {
int i, x;
cin >> i >> x;
if (a[i] != x) {
int old = a[i];
removeValue(old);
removeValue(x);
pos[old].erase(i);
a[i] = x;
pos[x].insert(i);
addValue(old);
addValue(x);
}
if (spans.empty()) {
cout << "0 0\n";
} else {
int k = *spans.rbegin();
cout << k << ' ' << ways[k] << '\n';
}
}
}
int main() {
setIO();
int t;
cin >> t;
while (t--) solve();
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll intervalWays(int l, int r) {
ll len = r - l + 1;
return len * (len + 1) / 2;
}
void solve() {
int n, q;
cin >> n >> q;
vector<int> a(n + 1);
vector<set<int>> pos(n + 1);
vector<set<pair<int, int>>> runs(n + 1);
vector<ll> ways(n + 1, 0);
multiset<int> spans;
auto addPoint = [&](int d, int p) {
int l = p, r = p;
auto it = runs[d].lower_bound({p + 1, -1});
if (it != runs[d].begin()) {
auto prv = prev(it);
if (prv->second + 1 == p) {
l = prv->first;
ways[d] -= intervalWays(prv->first, prv->second);
runs[d].erase(prv);
}
}
it = runs[d].lower_bound({p + 1, -1});
if (it != runs[d].end() && it->first == p + 1) {
r = it->second;
ways[d] -= intervalWays(it->first, it->second);
runs[d].erase(it);
}
runs[d].insert({l, r});
ways[d] += intervalWays(l, r);
};
auto removePoint = [&](int d, int p) {
auto it = prev(runs[d].upper_bound({p, n + 1}));
int l = it->first, r = it->second;
ways[d] -= intervalWays(l, r);
runs[d].erase(it);
if (l <= p - 1) {
runs[d].insert({l, p - 1});
ways[d] += intervalWays(l, p - 1);
}
if (p + 1 <= r) {
runs[d].insert({p + 1, r});
ways[d] += intervalWays(p + 1, r);
}
};
auto addValue = [&](int v) {
if ((int)pos[v].size() < 2) return;
int l = *pos[v].begin();
int r = *pos[v].rbegin();
int d = r - l;
spans.insert(d);
addPoint(d, l);
};
auto removeValue = [&](int v) {
if ((int)pos[v].size() < 2) return;
int l = *pos[v].begin();
int r = *pos[v].rbegin();
int d = r - l;
spans.erase(spans.find(d));
removePoint(d, l);
};
for (int i = 1; i <= n; i++) {
cin >> a[i];
pos[a[i]].insert(i);
}
for (int v = 1; v <= n; v++) addValue(v);
while (q--) {
int i, x;
cin >> i >> x;
if (a[i] != x) {
int old = a[i];
removeValue(old);
removeValue(x);
pos[old].erase(i);
a[i] = x;
pos[x].insert(i);
addValue(old);
addValue(x);
}
if (spans.empty()) {
cout << "0 0\n";
} else {
int k = *spans.rbegin();
cout << k << ' ' << ways[k] << '\n';
}
}
}
int main() {
setIO();
int t;
cin >> t;
while (t--) solve();
}