CF1479D Odd Mineral Resource
CF1000F
上树,考虑树上莫队。
同理,对值域分块,记 s u m i sum_i sumi 表示第 i i i 块值域出现次数为奇数的数的个数,再开个桶记录一下每个数的出现次数就行了,单次修改 O ( 1 ) \mathcal O(1) O(1)。
对于询问,同块暴力,否则从左散块,中整块,右散块判断,找到就结束,单次询问 O ( n ) \mathcal O(\sqrt n) O(n)。
说下树上莫队的细节:
- 建括号序,有两种情况,有一种需特判
LCA
(树剖维护)。 - 注意一些加加减减的细节问题,本人模拟赛因为这爆零。
综上,时间复杂度 O ( n n ) \mathcal O(n\sqrt n) O(nn),空间复杂度 O ( n ) \mathcal O(n) O(n), n n n 与值域同阶。
#include <bits/stdc++.h>
using namespace std;
#define he putchar('\n')
#define ha putchar(' ')
typedef long long ll;
inline int read() {
int x = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x;
}
inline void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
const int _ = 7e5 + 10;
int n, m, cnt, a[_], L[_], R[_], fn[_], ans[_];
int sq, bel[_];
vector<int> d[_];
void dfs(int u, int fa) {
fn[++cnt] = u, L[u] = cnt;
for (int v : d[u]) {
if (v == fa) continue;
dfs(v, u);
}
fn[++cnt] = u, R[u] = cnt;
}
int siz[_], dep[_], fa[_], hson[_], top[_];
void dfs1(int u, int D = 1) {
siz[u] = 1, dep[u] = D;
for (int v : d[u])
if (!siz[v]) {
fa[v] = u;
dfs1(v, D + 1);
siz[u] += siz[v];
if (siz[hson[u]] < siz[v]) hson[u] = v;
}
}
void dfs2(int u, int tf) {
top[u] = tf;
if (hson[u]) dfs2(hson[u], tf);
for (int v : d[u])
if (!top[v]) dfs2(v, v);
}
int LCA(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
u = fa[top[u]];
}
return dep[u] > dep[v] ? v : u;
}
struct Query {
int l, r, L, R, id, dd;
} q[_];
bool cmp(Query x, Query y) {
if (bel[x.L] != bel[y.L]) return x.L < y.L;
if (bel[x.L] & 1) return x.R < y.R;
return x.R > y.R;
}
int t[_], sum[_], lp[_], rp[_];
void upd(int x) {
if (t[x] & 1) sum[bel[x]]--;
else sum[bel[x]]++;
t[x] ^= 1;
}
signed main() {
n = read(), m = read();
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i < n; ++i) {
int x = read(), y = read();
d[x].push_back(y), d[y].push_back(x);
}
dfs(1, 0);
dfs1(1), dfs2(1, 1);
sq = sqrt(cnt) * 1.2;
for (int i = 1; i <= cnt; ++i) bel[i] = (i - 1) / sq + 1;
for (int i = 1; i <= bel[cnt]; ++i) lp[i] = rp[i - 1] + 1, rp[i] = min(cnt, i * sq);
for (int i = 1, u, v; i <= m; ++i) {
u = read(), v = read();
q[i].l = read(), q[i].r = read(), q[i].id = i;
if (L[u] > L[v]) swap(u, v);
if (R[u] < L[v]) q[i].L = R[u], q[i].R = L[v], q[i].dd = LCA(u, v);
else q[i].L = L[u], q[i].R = L[v];
}
sort(q + 1, q + m + 1, cmp);
int l = 0, r = 0;
for (int i = 1; i <= m; ++i) {
while (l > q[i].L) upd(a[fn[--l]]);
while (r < q[i].R) upd(a[fn[++r]]);
while (l < q[i].L) upd(a[fn[l++]]);
while (r > q[i].R) upd(a[fn[r--]]);
upd(a[fn[L[q[i].dd]]]);
bool flg = 0;
if (bel[q[i].l] == bel[q[i].r]) {
for (int j = q[i].l; j <= q[i].r; ++j)
if (t[j] & 1) {ans[q[i].id] = j, flg = 1;break;}
} else {
if (!flg) for (int j = q[i].l; j <= rp[bel[q[i].l]]; ++j) if (t[j] & 1) {ans[q[i].id] = j;flg = 1;break;}
if (!flg) for (int j = bel[q[i].l] + 1; j <= bel[q[i].r] - 1; ++j) if (sum[j]) {
for (int k = lp[j]; k <= rp[j]; ++k) if (t[k] & 1) {ans[q[i].id] = k;flg = 1;break;}
if (flg) break;
}
if (!flg) for (int j = lp[bel[q[i].r]]; j <= q[i].r; ++j) if (t[j] & 1) {ans[q[i].id] = j;flg = 1;break;}
}
if (!flg) ans[q[i].id] = -1;
upd(a[fn[L[q[i].dd]]]);
}
for (int i = 1; i <= m; ++i) write(ans[i]), he;
return 0;
}