constint N = 100010; typedeflonglong LL; int n, q, h[N], w[N], idx = 1; structEdge { int to, nxt; } e[N]; int fa[N], son[N], sz[N], dep[N], top[N], dfn[N], dfnw[N], ts; int rt = 1;
for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; dfs1(to); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ dfn[u] = ++ts, dfnw[ts] = w[u], top[u] = t; if (!son[u]) return; dfs2(son[u], t);
for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == son[u]) continue; dfs2(to, to); } }
voidupdate_path(int u, int v, int k){ while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); update(1, dfn[top[u]], dfn[u], k); u = fa[top[u]]; } if (dfn[u] > dfn[v]) swap(u, v); update(1, dfn[u], dfn[v], k); }
LL query_path(int u, int v){ LL res = 0; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); res += query(1, dfn[top[u]], dfn[u]); u = fa[top[u]]; } if (dfn[u] > dfn[v]) swap(u, v); res += query(1, dfn[u], dfn[v]); return res; }
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; }
// find u -> p -> v, where p near v. intfind(int u, int v){ while (top[u] != top[v]) { if (fa[top[u]] == v) return top[u]; u = fa[top[u]]; } return son[v]; }
LL query_tree(int u){ if (lca(u, rt) != u) returnquery(1, dfn[u], dfn[u]+sz[u]-1); LL res = query(1, 1, n); if (rt == u) return res;
int v = find(rt, u); return res - query(1, dfn[v], dfn[v]+sz[v]-1); }
voidupdate_tree(int u, int k){ if (lca(u, rt) != u) returnupdate(1, dfn[u], dfn[u]+sz[u]-1, k);
update(1, 1, n, k); if (rt == u) return; int v = find(rt, u); update(1, dfn[v], dfn[v]+sz[v]-1, -k); }
intmain(){ scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &w[i]); for (int i = 2; i <= n; i++) scanf("%d", &fa[i]), add(fa[i], i); dfs1(1); dfs2(1, 1); build(1, 1, n);
constint N = 30010, M = 60010, INF = 1e9; int h[N], w[N], n, q, idx = 1; structEdge { int to, nxt; } e[M]; int fa[N], sz[N], son[N], dep[N], top[N], dfn[N], dfnw[N], ts; structNode { int l, r; int sum, mx; } tr[N<<2];
voidbuild(int u, int l, int r){ tr[u].l = l, tr[u].r = r; if (l == r) return tr[u].sum = tr[u].mx = dfnw[l], void(); int mid = (l+r) >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); pushup(u); }
intquery_sum(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum; int mid = (tr[u].l + tr[u].r) >> 1; int res = 0; if (l <= mid) res += query_sum(u<<1, l, r); if (mid+1 <= r) res += query_sum(u<<1|1, l, r); return res; }
intquery_max(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) return tr[u].mx; int mid = (tr[u].l + tr[u].r) >> 1; int res = -INF; if (l <= mid) res = query_max(u<<1, l, r); if (mid+1 <= r) res = max(res, query_max(u<<1|1, l, r)); return res; }
voidupdate(int u, int p, int k){ if (tr[u].l == p && tr[u].r == p) { tr[u].sum = tr[u].mx = k; return; } int mid = (tr[u].l + tr[u].r) >> 1; if (p <= mid) update(u<<1, p, k); elseupdate(u<<1|1, p, k); pushup(u); }
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs1(int u, int father){ fa[u] = father, sz[u] = 1, dep[u] = dep[father]+1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == father) continue; dfs1(to, u); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ dfn[u] = ++ts, dfnw[ts] = w[u], top[u] = t;
if (!son[u]) return; dfs2(son[u], t);
for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa[u] || to == son[u]) continue; dfs2(to, to); } }
intquery_path_sum(int x, int y){ int res = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); res += query_sum(1, dfn[top[x]], dfn[x]); x = fa[top[x]]; } if (dfn[x] > dfn[y]) swap(x, y); res += query_sum(1, dfn[x], dfn[y]); return res; }
intquery_path_max(int x, int y){ int res = -INF; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); res = max(res, query_max(1, dfn[top[x]], dfn[x])); x = fa[top[x]]; } if (dfn[x] > dfn[y]) swap(x, y); res = max(res, query_max(1, dfn[x], dfn[y])); return res; }
voidupdate_vertex(int x, int k){ update(1, dfn[x], k); }
intmain(){ scanf("%d", &n); for (int i = 1, a, b; i < n; i++) scanf("%d%d", &a, &b), add(a, b), add(b, a); for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
voidbuild(int u, int l, int r){ tr[u].l = l, tr[u].r = r; if (l == r) return; int mid = (l+r) >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); }
voidupdate(int u, int l, int r, int k){ if (l <= tr[u].l && tr[u].r <= r) returnspread(u, k); pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (l <= mid) update(u<<1, l, r, k); if (mid+1 <= r) update(u<<1|1, l, r, k); pushup(u); }
LL query(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum; pushdown(u);
LL res = 0; int mid = (tr[u].l + tr[u].r) >> 1; if (l <= mid) res += query(u<<1, l, r); if (mid+1 <= r) res += query(u<<1|1, l, r); return res; }
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs1(int u){ sz[u] = 1, dep[u] = dep[fa[u]] + 1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; dfs1(to); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ dfn[u] = ++ts, top[u] = t; if (!son[u]) return; dfs2(son[u], t); for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == son[u]) continue; dfs2(to, to); } }
voidbuild(int u, int l, int r){ tr[u].l = l, tr[u].r = r, tr[u].flag = -1; if (l == r) return; int mid = (l+r) >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); }
intquery(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum; pushdown(u); int res = 0, mid = (tr[u].l + tr[u].r) >> 1; if (l <= mid) res += query(u<<1, l, r); if (mid+1 <= r) res += query(u<<1|1, l, r); return res; }
voidchange(int u, int l, int r, int v){ if (l <= tr[u].l && tr[u].r <= r) returnspread(u, v); pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (l <= mid) change(u<<1, l, r, v); if (mid+1 <= r) change(u<<1|1, l, r, v); pushup(u); }
intuninstall(int u){ int res = query(1, dfn[u], dfn[u]+sz[u]-1); change(1, dfn[u], dfn[u]+sz[u]-1, 0); return res; }
intinstall(int u){ int res = dep[u]; while (u) { res -= query(1, dfn[top[u]], dfn[u]); change(1, dfn[top[u]], dfn[u], 1); u = fa[top[u]]; } return res; }
intmain(){ scanf("%d", &n); for (int i = 2; i <= n; i++) { scanf("%d", &fa[i]), ++fa[i]; add(fa[i], i); } dfs1(1); dfs2(1, 1); build(1, 1, n);
scanf("%d", &q);
char op[10]; int x; while (q--) { scanf("%s%d", op, &x), ++x; if (*op == 'u') printf("%d\n", uninstall(x)); elseprintf("%d\n", install(x)); } return0; }
[SDOI2011] 染色
给定一棵 n 个节点的无根树,共有 m 个操作,操作分为两种:
将节点 a 到节点 b 的路径上的所有点(包括 a 和 b)都染成颜色 c。
询问节点 a 到节点 b 的路径上的颜色段数量。
颜色段的定义是极长的连续相同颜色被认为是一段。例如 112221 由三段组成:11、222、1。
输入格式
输入的第一行是用空格隔开的两个整数,分别代表树的节点个数 n 和操作个数 m。
第二行有 n 个用空格隔开的整数,第 i 个整数 wi 代表结点 i 的初始颜色。
第 3 到第 (n+1) 行,每行两个用空格隔开的整数 u,v,代表树上存在一条连结节点 u 和节点 v 的边。
第 (n+2) 到第 (n+m+1) 行,每行描述一个操作,其格式为:
每行首先有一个字符 op,代表本次操作的类型。
若 op 为 C,则代表本次操作是一次染色操作,在一个空格后有三个用空格隔开的整数 a,b,c,代表将 a 到 b 的路径上所有点都染成颜色 c。
若 op 为 Q,则代表本次操作是一次查询操作,在一个空格后有两个用空格隔开的整数 a,b,表示查询 a 到 b 路径上的颜色段数量。
输出格式
对于每次查询操作,输出一行一个整数代表答案。
数据规模与约定
对于 100% 的数据,1≤n,m≤105,1≤wi,c≤109,1≤a,b,u,v≤n,op 一定为 C 或 Q,保证给出的图是一棵树。
constint N = 100010, M = 200010; int a[N], n, m; int h[N], idx = 1; structEdge { int to, nxt; } e[M]; int fa[N], dep[N], top[N], son[N], dfn[N], dfnc[N], sz[N], ts;
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
structNode { int l, r; int lc, rc, cnt; int change; } tr[N<<2];
voidbuild(int u, int l, int r){ tr[u].l = l, tr[u].r = r; if (l == r) return; int mid = (l+r) >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); pushup(u); }
voidupdate(int u, int p){ if (tr[u].l == p && tr[u].r == p) return tr[u].right = p, void(); int mid = (tr[u].l + tr[u].r) >> 1; if (p <= mid) update(u<<1, p); elseupdate(u<<1|1, p); pushup(u); }
Node query(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) return tr[u]; int mid = (tr[u].l + tr[u].r) >> 1; if (l > mid) returnquery(u<<1|1, l, r); if (mid+1 > r) returnquery(u<<1, l, r); Node res = {0, 0, 0}; pushup(res, query(u<<1, l, r), query(u<<1|1, l, r)); return res; }
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs1(int u){ sz[u] = 1, dep[u] = dep[fa[u]]+1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; dfs1(to); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ top[u] = t, dfn[u] = ++ts, dfnid[ts] = u; if (!son[u]) return; dfs2(son[u], t); for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == son[u]) continue; dfs2(to, to); } }
intquery_path(int a){ while (a) { Node nd = query(1, dfn[top[a]], dfn[a]); if (nd.right) return dfnid[nd.right]; a = fa[top[a]]; } return0; }
voidupdate_vertex(int a){ update(1, dfn[a]); }
intmain(){ scanf("%d%d", &n, &q); for (int i = 1, a, f; i < n; i++) { scanf("%d%d", &f, &a); add(f, a); fa[a] = f; }
dfs1(1); dfs2(1, 1); build(1, 1, n);
update_vertex(1);
char tp[2]; for (int i = 1, a; i <= q; i++) { scanf("%s%d", tp, &a); if (*tp == 'C') update_vertex(a); elseprintf("%d\n", query_path(a)); }
return0; }
[国家集训队] 旅游
给定一棵 n 个节点的树,边带权,编号 0∼n−1,需要支持五种操作:
C i w 将输入的第 i 条边权值改为 w;
N u v 将 u,v 节点之间的边权都变为相反数;
SUM u v 询问 u,v 节点之间边权和;
MAX u v 询问 u,v 节点之间边权最大值;
MIN u v 询问 u,v 节点之间边权最小值。
保证任意时刻所有边的权值都在 [−1000,1000] 内。
输入格式
第一行一个正整数 n,表示节点个数。
接下来 n−1 行,每行三个整数 u,v,w,表示 u,v 之间有一条权值为 w 的边,描述这棵树。
voidbuild(int u, int l, int r){ tr[u].l = l, tr[u].r = r; if (l == r) { tr[u].sum = tr[u].max = tr[u].min = dfnw[l]; return; } int mid = (l+r) >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); pushup(u); }
Node query(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) return tr[u]; pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (l > mid) returnquery(u<<1|1, l, r); if (mid+1 > r) returnquery(u<<1, l, r); Node res = {0, 0, 0, 0, 0, 0}; pushup(res, query(u<<1, l, r), query(u<<1|1, l, r)); return res; }
voidupdate(int u, int p, int k){ if (tr[u].l == p && tr[u].r == p) { tr[u].max = tr[u].min = tr[u].sum = k; return; } pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (p <= mid) update(u<<1, p, k); elseupdate(u<<1|1, p, k); pushup(u); }
voidflip(int u, int l, int r){ if (l <= tr[u].l && tr[u].r <= r) returnspread(u); pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (l <= mid) flip(u<<1, l, r); if (mid+1 <= r) flip(u<<1|1, l, r); pushup(u); }
voidadd(int a, int b, int c){ e[idx] = {b, c, h[a]}, h[a] = idx++; }
voiddfs1(int u, int father, int weight){ fa[u] = father, w[u] = weight; sz[u] = 1, dep[u] = dep[father] + 1;
for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == father) continue; dfs1(to, u, e[i].w); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ dfn[u] = ++ts, dfnw[ts] = w[u], top[u] = t; if (!son[u]) return; dfs2(son[u], t);
for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa[u] || to == son[u]) continue; dfs2(to, to); } }
intlca(int a, int b){ while (top[a] != top[b]) { if (dep[top[a]] < dep[top[b]]) swap(a, b); a = fa[top[a]]; } return dep[a] > dep[b] ? b : a; }
Node query_path(int a, int b){ int u = lca(a, b);
vector<Node> nodes; while (top[a] != top[u]) { nodes.push_back(query(1, dfn[top[a]], dfn[a])); a = fa[top[a]]; } if (a != u) nodes.push_back(query(1, dfn[son[u]], dfn[a]));
while (top[b] != top[u]) { nodes.push_back(query(1, dfn[top[b]], dfn[b])); b = fa[top[b]]; } if (b != u) nodes.push_back(query(1, dfn[son[u]], dfn[b]));
Node res = nodes[0]; for (int i = 1; i < nodes.size(); i++) { Node l = res; pushup(res, l, nodes[i]); } return res; }
voidupdate_edge(int u, int k){ int a = e[u<<1].to, b = e[u<<1|1].to; if (dep[a] < dep[b]) swap(a, b); update(1, dfn[a], k); }
voidflip_path(int a, int b){ int u = lca(a, b);
while (top[a] != top[u]) { flip(1, dfn[top[a]], dfn[a]); a = fa[top[a]]; } if (a != u) flip(1, dfn[son[u]], dfn[a]);
while (top[b] != top[u]) { flip(1, dfn[top[b]], dfn[b]); b = fa[top[b]]; } if (b != u) flip(1, dfn[son[u]], dfn[b]); }
intmain(){ scanf("%d", &n); for (int i = 1, a, b, c; i < n; i++) { scanf("%d%d%d", &a, &b, &c); ++a, ++b; add(a, b, c), add(b, a, c); }
dfs1(1, 0, 0); dfs2(1, 1); build(1, 1, n);
char op[5]; scanf("%d", &m); for (int i = 1, a, b; i <= m; i++) { scanf("%s%d%d", op, &a, &b); ++a, ++b; if (op[0] == 'C') update_edge(a-1, b-1); elseif (op[0] == 'N') flip_path(a, b); elseif (op[0] == 'S') printf("%d\n", query_path(a, b).sum); elseif (op[1] == 'A') printf("%d\n", query_path(a, b).max); elseprintf("%d\n", query_path(a, b).min); }
return0; }
[CF1023F] Mobile Phone Network
给定 k 条未确定边权的边(不构成环),然后给 m 个确定边权的边,对这些边确定合适的边权,使得所有点都连通的情况下:
constint N = 500010, M = 1000010, INF = 1e9+7; int h[N], n, m, k, idx = 1; int dep[N], w[N], son[N], fa[N], top[N], sz[N]; int dfn[N], dfnw[N], ts; int p[N];
structEdgeE { int to, nxt, w; } e[M];
structEdge { int a, b, w; bool used = false; booloperator<(const Edge& e) const { return w < e.w; } }; vector<Edge> edges; vector<Edge> spec;
structNode { int l, r; int mn; } tr[N<<2];
voidadd(int a, int b, int c){ e[idx] = {b, h[a], c}, h[a] = idx++; }
voiddfs1(int u, int father, int weight){ fa[u] = father, w[u] = weight, sz[u] = 1, dep[u] = dep[father]+1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == father) continue; dfs1(to, u, e[i].w); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ dfn[u] = ++ts, dfnw[ts] = w[u], top[u] = t; if (!son[u]) return; dfs2(son[u], t); for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == son[u] || to == fa[u]) continue; dfs2(to, to); } }
voidspread(int u, int v){ tr[u].mn = min(tr[u].mn, v); }
voidbuild(int u, int l, int r){ tr[u].l = l, tr[u].r = r; tr[u].mn = INF; if (l == r) return tr[u].mn = dfnw[l], void(); int mid = (l+r) >> 1; build(u<<1, l, mid), build(u<<1|1, mid+1, r); }
intquery(int u, int p){ if (tr[u].l == p && tr[u].r == p) return tr[u].mn; pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (p <= mid) returnquery(u<<1, p); returnquery(u<<1|1, p); }
voidupdate(int u, int l, int r, int k){ if (l <= tr[u].l && tr[u].r <= r) returnspread(u, k); pushdown(u); int mid = (tr[u].l + tr[u].r) >> 1; if (l <= mid) update(u<<1, l, r ,k); if (mid+1 <= r) update(u<<1|1, l, r, k); }
intlca(int a, int b){ while (top[a] != top[b]) { if (dep[top[a]] < dep[top[b]]) swap(a, b); a = fa[top[a]]; } return dep[a] > dep[b] ? b : a; }
voidupdate_path(int a, int b, int w){ int u = lca(a, b); while (top[a] != top[u]) { update(1, dfn[top[a]], dfn[a], w); a = fa[top[a]]; } if (a != u) update(1, dfn[son[u]], dfn[a], w);
while (top[b] != top[u]) { update(1, dfn[top[b]], dfn[b], w); b = fa[top[b]]; } if (b != u) update(1, dfn[son[u]], dfn[b], w); }
intmain(){ scanf("%d%d%d", &n, &k, &m);
for (int i = 1; i <= n; i++) p[i] = i;
int a, b, c; for (int i = 1; i <= k; i++) { scanf("%d%d", &a, &b); p[find(a)] = find(b); add(a, b, INF), add(b, a, INF); Edge edg; edg.a = a, edg.b = b, edg.w = 0; spec.push_back(edg); }
for (int i = 1; i <= m; i++) { scanf("%d%d%d", &a, &b, &c); Edge edg; edg.a = a, edg.b = b, edg.w = c; edges.push_back(edg); } // kruskal sort(edges.begin(), edges.end()); for (auto& edge: edges) { int a = edge.a, b = edge.b, w = edge.w; if (find(a) != find(b)) { p[find(a)] = find(b); add(a, b, w), add(b, a, w); edge.used = true; } }
dfs1(1, 0, 0); dfs2(1, 1); build(1, 1, n);
for (constauto& edge: edges) { if (edge.used) continue; update_path(edge.a, edge.b, edge.w); }
longlong res = 0; for (constauto& edge: spec) { int a = edge.a, b = edge.b; if (dep[a] < dep[b]) swap(a, b); int cost = query(1, dfn[a]); if (cost == INF) puts("-1"), exit(0); res += cost; }
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs1(int u){ sz[u] = 1, dep[u] = dep[fa[u]] + 1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; dfs1(to); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ top[u] = t, dfn[u] = ++ts; if (!son[u]) return; dfs2(son[u], t);
for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == son[u]) continue; dfs2(to, to); } }
intlca(int a, int b, int& sum){ while (top[a] != top[b]) { if (dep[top[a]] < dep[top[b]]) swap(a, b); sum += query(dfn[top[a]], dfn[a]); a = fa[top[a]]; } if (dfn[a] > dfn[b]) swap(a, b); sum += query(dfn[a], dfn[b]); return a; }
vector<Query1> qry1; queue<Query2> qry2; int ans1[N], ans2[N];
intmain(){ scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &fa[i]); if (fa[i]) add(fa[i], i); else rt = i; } scanf("%d", &q); for (int i = 1, tp, x, y, c; i <= q; i++) { scanf("%d", &tp); if (tp == 1) scanf("%d%d%d", &x, &y, &c), qry1.push_back({x, y, c, i}); elsescanf("%d", &x), qry2.push({x, i}); } sort(qry1.begin(), qry1.end()); dfs1(rt), dfs2(rt, rt);
for (const Query1& qry: qry1) { while (qry2.size()) { int t = qry2.front().t, u = qry2.front().u; if (qry.t - qry.c <= t) break; modify(dfn[u], 1); qry2.pop(); }
int a = qry.x, b = qry.y; int u = lca(a, b, ans2[qry.t]); ans1[qry.t] = dep[a] + dep[b] - 2*dep[u] + 1; }
for (int i = 1; i <= q; i++) if (ans1[i]) printf("%d %d\n", ans1[i], ans2[i]);