int sq; structQuery { int l, r, id; booloperator < (const Query &o) const { if (l / sq != o.l / sq) return l < o.l; if (l / sq & 1) return r < o.r; return r > o.r; } } q[N];
int a[N], ans[N], cnt[N], cur, l = 1, r = 0;
inlinevoidadd(int p) { if (cnt[a[p]] == 0) cur ++; cnt[a[p]] ++; }
inlinevoiddel(int p) { cnt[a[p]] --; if (cnt[a[p]] == 0) cur --; }
intmain() { scanf ("%d", &n); sq = sqrt (n); for (int i = 1; i <= n; i ++) scanf ("%d", &a[i]); scanf ("%d", &m); for (int i = 0; i < m; i ++) { scanf ("%d %d", &q[i].l, &q[i].r); q[i].id = i; } sort (q, q + m); for (int i = 0; i < m; i ++) { while (l > q[i].l) add (-- l); while (r < q[i].r) add (++ r); while (l < q[i].l) del (l ++); while (r > q[i].r) del (r --); ans[q[i].id] = cur; } }
structQuery { int id, l, r, t; int lca; boolfriendoperator < (Query a, Query b) { if (bel[a.l] == bel[b.l]) { if (bel[a.r] == bel[b.r]) { if (bel[a.r] & 1) return a.t < b.t; else return a.t > b.t; } if (bel[a.l] & 1) return a.r < b.r; else return a.r > b.r; } else return a.l < b.l; } } q[N];
int head[N], cnt; int n, m, qs, v[N], w[N], c[N], tmp[N], num1, num2, ans[N]; int dep[N], fa[N][19]; int a[N << 1], tot, in[N], out[N], buc[N]; int vis[N], now;
structEvent {// 记录修改 int x, fr, to; } h[N];
inlinevoidadd_edge(int u, int v) { edge[++ cnt].to = v; edge[cnt].nxt = head[u]; head[u] = cnt; }
voiddfs(int x, int depth)// 预处理出父亲、欧拉序、深度 { dep[x] = depth; a[++ tot] = x; in[x] = tot; for (int i = head[x]; i; i = edge[i].nxt) { int y = edge[i].to; if (y == fa[x][0]) continue; fa[y][0] = x; dfs (y, depth + 1); } a[++ tot] = x; out[x] = tot; }
inlineintlca(int x, int y)// lca 板子 { if (dep[x] < dep[y]) swap (x, y); for (int i = 18; i >= 0; i --) if (dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i --) if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } return fa[x][0]; }
inlinevoidupdate(int id, int c)// 这里只需要写一个 update,记录贡献,如果重复就删掉了 { if (c == 1) now += v[id] * w[buc[id] + 1]; else now -= v[id] * w[buc[id]]; buc[id] += c; // 也可以写 ^ 的 }
inlinevoidchange(int x, int o) { int pos = a[x]; if (vis[pos] & 1) update (c[pos], -1); else update (c[pos], 1); vis[pos] += o; }
inlinevoidadd_edge(int u, int v) { edge[++ edgecnt].to = v; edge[edgecnt].nxt = head[u]; head[u] = edgecnt; }
voiddfs(int x, int depth) { dep[x] = depth; a[++ tot] = x; in[x] = tot; for (int i = head[x]; i; i = edge[i].nxt) { int y = edge[i].to; if (y == fa[x][0]) continue; fa[y][0] = x; dfs (y, depth + 1); } a[++ tot] = x; out[x] = tot; }
inlineintLCA(int x, int y) { if (dep[x] < dep[y]) swap (x, y); for (int i = 18; i >= 0; i --) if (dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i --) if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } return fa[x][0]; }
voidadd(int x) { if (vis[x]) { cnt[c[x]] --; if (cnt[c[x]] == 0) ans --; } else { cnt[c[x]] ++; if (cnt[c[x]] == 1) ans ++; } vis[x] ^= 1; }
intmain() { scanf ("%d %d", &n, &m); sq = sqrt (n); for (int i = 1; i <= n; i ++) { scanf ("%d", &c[i]); temp[i] = c[i]; } sort (temp + 1, temp + n + 1); int size = unique (temp + 1, temp + n + 1) - temp - 1; for (int i = 1; i <= n; i ++) c[i] = lower_bound (temp + 1, temp + size + 1, c[i]) - temp; for (int i = 1; i < n; i ++) { int x, y; scanf ("%d %d", &x, &y); add_edge (x, y); add_edge (y, x); } dfs (1, 1); for (int j = 1; j <= 17; j ++) for (int i = 1; i <= n; i ++) fa[i][j] = fa[fa[i][j - 1]][j - 1]; for (int i = 1; i <= m; i ++) { int x, y, lca; scanf ("%d %d", &x, &y); lca = LCA (x, y); if (in[y] < in[x]) swap (x, y); if (x == lca) q[i] = (Query) {in[x], in[y], 0, i}; else q[i] = (Query) {out[x], in[y], lca, i}; } sort (q + 1, q + m + 1); int ql = 1, qr = 0; for (int i = 1; i <= m; i ++) { while (ql < q[i].l) { add (a[ql]); ++ ql; } while (ql > q[i].l) { -- ql; add (a[ql]); } while (qr < q[i].r) { ++ qr; add (a[qr]); } while (qr > q[i].r) { add (a[qr]); -- qr; } if (q[i].add) add (q[i].add); res[q[i].id] = ans; if (q[i].add) add (q[i].add); } for (int i = 1; i <= m; i ++) printf ("%d\n", res[i]); return0; }
inlineintcalc(int l, int r)// 计算贡献 { int res = 0; for (int i = l; i <= r; i ++) tmp[a[i]] = 0; for (int i = l; i <= r; i ++) { tmp[a[i]] ++; res = max (res, tmp[a[i]] * u[a[i]]); } return res; }
inlinevoidadd(int x) { cnt[x] ++; now = max (now, cnt[x] * u[x]); }
inlinevoiddel(int x) { cnt[x] --; }
inlinevoidwork() { int L = sq, R = L - 1, pl = L; for (int i = 1; i <= m; i ++) { if (bel[q[i - 1].l] < bel[q[i].l]) // 不在同一块内 { L = (bel[q[i].l] + 1) * sq; R = L - 1; memset (cnt, 0, sizeof cnt); pl = L; cur = now = 0; } if (bel[q[i].l] == bel[q[i].r]) // 在同一块内 { ans [q[i].id] = calc (q[i].l, q[i].r); // 直接暴力处理 continue; } while (R < q[i].r) add (a[++ R]); // 扩展右端点 cur = now; while (q[i].l < L) add (a[-- L]); // 扩展左端点 ans[q[i].id] = now; // 回答询问 while (L < pl) // 撤销左端点改动 del (a[L ++]); now = cur; } }
signedmain() { scanf ("%lld %lld", &n, &m); sq = sqrt (n); for (int i = 1; i <= n; i ++) { scanf ("%lld", &a[i]); bel[i] = i / sq; u[i] = a[i]; } sort (u + 1, u + n + 1); tot = unique (u + 1, u + n + 1) - u - 1; for (int i = 1; i <= n; i ++) a[i] = lower_bound (u + 1, u + tot + 1, a[i]) - u; for (int i = 1; i <= m; i ++) { scanf ("%lld %lld", &q[i].l, &q[i].r); q[i].id = i; } sort (q + 1, q + m + 1); work (); for (int i = 1; i <= m; i ++) printf ("%lld\n", ans[i]); return0; }
inlinevoidremove(int p, int &Minval)// 这是删点 { if (a[p] > n + 1) return ; cnt[a[p]] --; if (cnt[a[p]] == 0) Minval = min (Minval, a[p]); }
inlinevoidresume(int p)// 这是撤 { if (a[p] > n + 1) return ; cnt[a[p]] ++; }
voidwork()// 莫队板子不像这 { sort (q + 1, q + m + 1); int l = 1, r = n, pl = 0; for (int i = 1; i <= m; i ++) { if (bel[q[i].l] == bel[q[i].r]) // 同一块内询问 { for (int j = q[i].l; j <= q[i].r; j ++) if (a[j] <= n + 1) tot[a[j]] ++; int temp = 0; while (tot[temp]) temp ++; ans[q[i].id] = temp; for (int j = q[i].l; j <= q[i].r; j ++) if (a[j] <= n + 1) tot[a[j]] --; continue; } if (bel[q[i].l] ^ pl) // 到了一个新块,先初始化左右端点 { while (r < n) resume (++ r); while (l < L[bel[q[i].l]]) remove (l ++, res); minn = res; pl = bel[q[i].l]; } while (r > q[i].r) // 移动右端点 remove (r --, minn); int temp = minn, cl = l; while (cl < q[i].l) // 移动左端点回答询问 remove (cl ++, temp); while (cl > l) // 咱,撤! resume (-- cl); ans[q[i].id] = temp; } }
intmain() { scanf ("%d %d", &n, &m); for (int i = 1; i <= n; i ++) scanf ("%d", &a[i]); for (int i = 1; i <= m; i ++) { scanf ("%d %d", &q[i].l, &q[i].r); q[i].id = i; } for (int i = 1; i <= n; i ++) if (a[i] <= n + 1) cnt[a[i]] ++; // 将整个序列加入桶,同时得到整体答案 while (cnt[res]) res ++; sq = sqrt (n); t = n / sq; for (int i = 1; i <= t; i ++) { if (i * sq > n) break; L[i] = (i - 1) * sq + 1; R[i] = i * sq; } if (R[t] < n) { t ++; L[t] = R[t - 1] + 1; R[t] = n; } for (int i = 1; i <= t; i ++) for (int j = L[i]; j <= R[i]; j ++) bel[j] = i; work (); for (int i = 1; i <= m; i ++) printf ("%d\n", ans[i]); return0; }
for (int i = 1; i <= n; i ++) { num1[i] += (i - 1 - tr_sum (c[i])); tr_add (c[i], 1); sum1[i] = sum[i - 1] + num1[i]; } for (int i = n; i >= 1; i --) { num2[i] += tr_sum (c[i] - 1); tr_add (c[i], 1); sum2[i] = sum2[i + 1] + num2[i]; }
然后去写个数状数组的板子:
1 2 3 4 5 6 7 8 9 10 11 12
inlinevoidtr_add(int x, int k) { for (int i = x; i <= n; i += lowbit (i)) tree[i] += k; } inlineinttr_sum(int x) { int res = 0; for (int i = x; i; i -= lowbit (i)) res += tree[i]; return res; }
inlineboolcmp1(Query a, Query b) { return (a.l / tot == b.l / tot) ? a.r < b.r : a.l < b.l; }
inlineboolcmp2(Query a, Query b) { return a.l < b.l; }
inlineintlowbit(int x) { return x & -x; }
inlinevoidtr_add(int x, int k) { for (int i = x; i <= n; i += lowbit (i)) tree[i] += k; }
inlineinttr_sum(int x) { int res = 0; for (int i = x; i; i -= lowbit (i)) res += tree[i]; return res; }
inlinevoidadd1(int x, int p, int k1, int k2, int id) { vec1[x].push_back ((Node) {p, k1, k2, id}); }
inlinevoidadd2(int x, int p, int k1, int k2, int id) { vec2[x].push_back ((Node) {p, k1, k2, id}); }
voidpushup1(int x) { if (ad[bel[x]]) for (int i = L[bel[x]]; i <= R[bel[x]]; i ++) w[i] += ad[bel[x]]; ad[bel[x]] = 0; for (int i = L[bel[x]]; i <= x; i ++) ++ w[i]; for (int i = 1; i <= bel[x] - 1; i ++) ++ ad[i]; }
voidpushup2(int x) { if (ad[bel[x]]) for (int i = L[bel[x]]; i <= R[bel[x]]; i ++) w[i] += ad[bel[x]]; ad[bel[x]] = 0; for (int i = x; i <= R[bel[x]]; i ++) ++ w[i]; for (int i = bel[x] + 1; i <= sz; i ++) ++ ad[i]; }
voidsolve() { cnt = sqrt (idnum); sz = 1; L[sz] = 1; if (cnt * cnt < idnum) ++ cnt; for (int i = 1; i <= idnum; i ++) { bel[i] = sz; if (i % cnt == 0) { R[sz] = i; L[++ sz] = i + 1; } } R[sz] = idnum; for (int i = 1; i <= n; i ++) { int fr, ed, id; longlong p; for (int j = 0; j < vec1[i].size (); j ++) { id = vec1[i][j].id; p = 1ll * vec1[i][j].p; fr = vec1[i][j].l; ed = vec1[i][j].r; for (int k = fr; k <= ed; k ++) ans[id] += 1ll * p * (ad[bel[c[k] + 1]] + w[c[k] + 1]); } pushup1 (c[i]); } memset (ad, 0, sizeof ad); memset (w, 0, sizeof w); for (int i = n; i >= 1; i --) { int fr, ed, id; longlong p; for (int j = 0; j < vec2[i].size (); j ++) { id = vec2[i][j].id; p = 1ll * vec2[i][j].p; fr = vec2[i][j].l; ed = vec2[i][j].r; for (int k = fr; k <= ed; k ++) ans[id] += 1ll * p * (ad[bel[c[k] - 1]] + w[c[k] - 1]); } pushup2 (c[i]); } }
intmain() { scanf ("%d %d", &n, &m); tot = 355; for (int i = 1; i <= n; i ++) { scanf ("%d", &c[i]); p[i].l = c[i]; p[i].id = i; } sort (p + 1, p + n + 1, cmp2); p[0].l = -1; for (int i = 1; i <= n; i ++) c[p[i].id] = (idnum += (p[i].l != p[i - 1].l)); for (int i = 1; i <= m; i ++) { scanf ("%d %d", &q[i].l, &q[i].r); q[i].id = i; } for (int i = 1; i <= n; i ++) { num1[i] += (i - 1 - tr_sum (c[i])); tr_add (c[i], 1); sum1[i] = sum1[i - 1] + num1[i]; } memset (tree, 0, sizeof tree); for (int i = n; i >= 1; i --) { num2[i] += tr_sum (c[i] - 1); tr_add (c[i], 1); sum2[i] = sum2[i + 1] + num2[i]; } sort (q + 1, q + m + 1, cmp1); int l = 1, r = 0; for (int i = 1; i <= m; i ++) { if (r < q[i].r) { ans[q[i].id] += (sum1[q[i].r] - sum1[r]); add1 (l, -1, r + 1, q[i].r, q[i].id); r = q[i].r; } if (r > q[i].r) { ans[q[i].id] -= (sum1[r] - sum1[q[i].r]); add1 (l, 1, q[i].r + 1, r, q[i].id); r = q[i].r; } if (l < q[i].l) { ans[q[i].id] -= (sum2[l] - sum2[q[i].l]); add2 (r, 1, l, q[i].l - 1, q[i].id); l = q[i].l; } if (l > q[i].l) { ans[q[i].id] += (sum2[q[i].l] - sum2[l]); add2 (r, -1, q[i].l, l - 1, q[i].id); l = q[i].l; } } solve (); for (int i = 1; i <= m; i ++) ans[q[i].id] += ans[q[i - 1].id]; for (int i = 1; i <= m; i ++) printf ("%lld\n", ans[i]); return0; }