int n, m, a[MAXN], SIZE; #define bel(i) (i / SIZE + 1)
structquery { int l, r, a, b, id; }que[MAXN];
structBIt { int lim, t[MAXN]; #define lowbit(i) (i & -i) voidinit(int x){lim = x;} voidadd(int i, int val) { if (!i) return; while (i <= lim) t[i] += val, i += lowbit(i); } intquery(int i, int res = 0) { while (i) res += t[i], i -= lowbit(i); return res; }
}t1, t2;
int cnt[MAXN]; voidadd(int pos) { if (cnt[a[pos]] == 0) t2.add(a[pos], 1); cnt[a[pos]]++; t1.add(a[pos], 1); } voiddel(int pos) { if (cnt[a[pos]] == 1) t2.add(a[pos], -1); cnt[a[pos]]--; t1.add(a[pos], -1); }
int ans1[MAXN], ans2[MAXN];
intmain() { read(n, m); SIZE = sqrt(n); int mxz = 0; for (int i = 1; i <= n; i++) read(a[i]); for (int i = 1; i <= m; i++) { int l, r, a, b; read(l, r, a, b); que[i] = {l, r, a - 1, b, i}; mxz = max({mxz, a, b}); } t1.init(mxz); t2.init(mxz); sort(que + 1, que + 1 + m, [&](query a, query b) { if (bel(a.l) != bel(b.l)) return a.l < b.l; returnbel(a.l) & 1 ? a.r < b.r : a.r > b.r; });
int L = 1, R = 0; for (int i = 1; i <= m; i++) { int l = que[i].l, r = que[i].r; while (L > l) add(--L); while (R < r) add(++R); while (L < l) del(L++); while (R > r) del(R--); ans1[que[i].id] = t1.query(que[i].b) - t1.query(que[i].a); ans2[que[i].id] = t2.query(que[i].b) - t2.query(que[i].a); } for (int i = 1; i <= m; i++) print(ans1[i], ' '), print(ans2[i], '\n');
intmain() { n = read(); m = read(); for (int i = 1; i <= n; i++) a[i] = h[i] = read(); BK::pre_block(); pre_lsh(); for (int i = 1; i <= m; i++) { q[i].l = read(); q[i].r = read(); q[i].id = i; }
sort(q + 1, q + 1 + m, cmp);
int last = 0; // 上一个询问左端点所在块 for (int i = 1; i <= m; i++) { int l = q[i].l, r = q[i].r;
if (bel[l] == bel[r]) // 一个块内,直接暴力 { for (int j = l; j <= r; j++) { cut[a[j]]++; ans[q[i].id] = max(ans[q[i].id], h[a[j]]*1LL*cut[a[j]]); } for (int j = l; j <= r; j++) cut[a[j]]--; continue; } if (bel[l] != last) // 到达新块,初始化 { while(R > BK::R[bel[l]]) del(R--); while(L < BK::R[bel[l]]+1) del(L++); Ans = 0; last = bel[l]; }
while (R < r) add(++R, Ans); // 添加右端点 int LL = L; ll res = Ans; // 备份答案,处理左端点的移动 while (LL > l) add(--LL, res); while (LL < L) del(LL++); // 删除左端点 ans[q[i].id] = res;
}
for (int i = 1 ; i <= m; i++) printf("%lld\n", ans[i]);
int n, m, SIZE; int a[MAXN], b[MAXN]; int bel[MAXN];
structquery { int l, r, u, v, id, lca; }que[MAXM];
boolcmp(query a, query b) { if (bel[a.l] != bel[b.l]) return bel[a.l] < bel[b.l]; if (bel[a.l] % 2) return a.r < b.r; elsereturn a.r > b.r; }
vector <int> e[MAXN];
int euler_cnt; int euler[MAXN*2], in[MAXN], out[MAXN]; int siz[MAXN], dep[MAXN], fa[MAXN], top[MAXN], son[MAXN];
// dfs 整括号序,顺便树剖LCA voiddfs1(int u, int dad) { euler[in[u] = ++euler_cnt] = u; // 括号序中第一次出现 fa[u] = dad; siz[u] = 1; dep[u] = dep[dad] + 1; for (int v : e[u]) if (v != dad) { dfs1(v, u); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } euler[out[u] = ++euler_cnt] = u; // 括号序中第二次出现 }
voiddfs2(int u, int tup) { top[u] = tup; if (son[u]) dfs2(son[u], tup); for (int v : e[u]) if (v != son[u] && v != fa[u]) { dfs2(v, v); } }
intLCA(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] ? u : v; }
int L = 1, R = 0, Ans; int cnt[MAXM]; int vis[MAXN]; // 记录第一次还是第二次
voidadd(int pos) { cnt[a[pos]]++; if (cnt[a[pos]] == 1) Ans++; }
voiddel(int pos) { cnt[a[pos]]--; if (cnt[a[pos]] == 0) Ans--; }
voidchange(int pos) { int u = euler[pos]; vis[u] ? del(u) : add(u); vis[u] ^= 1; }
int ans[MAXM];
intmain() { read(n, m); for (int i = 1; i <= n; i++) { read(a[i]); b[i] = a[i]; } // 离散化 sort(b + 1, b + 1 + n); int len = unique(b + 1, b + 1 + n) - b - 1; for (int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + len, a[i]) - b; for (int i = 1; i < n; i++) { int u, v; read(u, v); e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0); dfs2(1, 1); SIZE = pow(euler_cnt, 0.5); // 括号序上莫队,注意块长 for (int i = 1; i <=euler_cnt; i++) bel[i] = i / SIZE + 1;
for (int i = 1; i <= m; i++) { int u, v; read(u, v); que[i].id = i; if (in[u] > in[v]) swap(u, v); // 先后顺序 que[i].u = u; que[i].v = v; // 根据 LCA 分情况 if (u == LCA(u, v)) { que[i].l = in[u]; que[i].r = in[v]; que[i].lca = 0; } else { que[i].l = out[u]; que[i].r = in[v]; que[i].lca = LCA(u, v); } } sort(que+1, que+1+m, cmp); for (int i = 1; i <= m; i++) { int l = que[i].l, r = que[i].r; while (L > l) change(--L); while (L < l) change(L++); while (R < r) change(++R); while (R > r) change(R--); // 特判 LCA if (que[i].lca) change(in[que[i].lca]); ans[que[i].id] = Ans; if (que[i].lca) change(in[que[i].lca]); } for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
根据游客们的反馈打分,我们得到了糖果的美味指数, 第 i 种糖果的美味指数为 Vi。另外,如果一位游客反复地品尝同一种类的糖果,他肯定会觉得有一些腻。根据量化统计,我们得到了游客第 i 次品尝某类糖果的新奇指数 Wi。如果一位游客第 i 次品尝第 j 种糖果,那么他的愉悦指数 H 将会增加对应的美味指数与新奇指数的乘积,即 Vj×Wi。这位游客游览公园的愉悦指数最终将是这些乘积的和。
糖果公园的工作人员小 A 接到了一个任务,那就是根据公园最近的数据统计出每位游客游玩公园的愉悦指数。但数学不好的小 A 一看到密密麻麻的数字就觉得头晕,作为小 A 最好的朋友,你决定帮他一把。
voidchange(int T) { int pos = mdf[T].pos; if (vis[pos]) { work(pos); swap(mdf[T].val, c[pos]); work(pos); } elseswap(mdf[T].val, c[pos]); }
intmain() { read(n, m, q); for (int i = 1; i <= m; i++) read(v[i]); for (int i = 1; i <= n; i++) read(w[i]); for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); e[u].push_back(v); e[v].push_back(u); } for (int i = 1; i <= n; i++) read(c[i]); dfs1(1, 0); dfs2(1, 1); SIZE = pow(euler_cnt, 0.66666667);
for (int i = 1; i <= q; i++) { int op, x, y; read(op, x, y); if (op == 1) { cntq++; if (in[x] > in[y]) swap(x, y); int lca = LCA(x, y); if (x == lca) que[cntq] = { in[x], in[y], x, y, 0 , cntc, cntq}; else que[cntq] = { out[x], in[y], x, y, lca, cntc, cntq}; } else { mdf[++cntc] = {x, y}; } } sort(que+1, que+1+cntq, cmp); for (int i = 1; i <= q; i++) { int l = que[i].l, r = que[i].r, t = que[i].t; while (L > l) work(euler[--L]); while (L < l) work(euler[L++]); while (R < r) work(euler[++R]); while (R > r) work(euler[R--]); while (T < t) change(++T); while (T > t) change(T--); if (que[i].lca) work(que[i].lca); ans[que[i].id] = Ans; if (que[i].lca) work(que[i].lca); } for (int i = 1; i <= cntq; i++) printf("%lld\n", ans[i]);