「LNOI2014」LCA

传送门

这里要用到一个巧妙的想法:我们可以把加上 \(dep_u\) 转化为节点到根路径加和路径查询。

然后题目要求的是一段区间编号的点对某个点求 \(\text{LCA}\),可以考虑离线,然后我们把这道题转化成了树上路径加以及查询。

写个树剖就没了。

参考代码:

Copy
#include <algorithm> #include <cstdio> using namespace std; const int _ = 1e5 + 5, mod = 201314; template < class T > void read(T& s) { s = 0; int f = 0; char c = getchar(); while ('0' > c || c > '9') f |= c == '-', c = getchar(); while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar(); s = f ? -s : s; } int tot, head[_]; struct Edge { int v, nxt; } edge[_ << 1]; void Add_edge(int u, int v) { edge[++tot] = (Edge) { v, head[u] }, head[u] = tot; } int n, q, ans[_], cnt; struct node { int x, y, opt, id; } t[_ << 1]; int cmp(node a, node b) { return a.x < b.x; } int dep[_], siz[_], son[_], dfn[_], top[_], fa[_], sum[_ << 2], tag[_ << 2]; int lc(int p) { return p << 1; } int rc(int p) { return p << 1 | 1; } void pushup(int p) { sum[p] = (sum[lc(p)] + sum[rc(p)]) % mod; } void add(int p, int v, int l, int r) { sum[p] = (sum[p] + v * (r - l + 1) % mod) % mod, tag[p] = (tag[p] + v) % mod; } void pushdown(int p, int l, int r, int mid) { if (tag[p]) add(lc(p), tag[p], l, mid), add(rc(p), tag[p], mid + 1, r), tag[p] = 0; } void update(int ql, int qr, int v, int p = 1, int l = 1, int r = n) { if (ql <= l && r <= qr) return add(p, v, l, r); int mid = (l + r) >> 1; pushdown(p, l, r, mid); if (ql <= mid) update(ql, qr, v, lc(p), l, mid); if (qr > mid) update(ql, qr, v, rc(p), mid + 1, r); pushup(p); } int query(int ql, int qr, int p = 1, int l = 1, int r = n) { if (ql <= l && r <= qr) return sum[p]; int mid = (l + r) >> 1, res = 0; pushdown(p, l, r, mid); if (ql <= mid) res = (res + query(ql, qr, lc(p), l, mid)) % mod; if (qr > mid) res = (res + query(ql, qr, rc(p), mid + 1, r)) % mod; return res; } void dfs(int u, int f) { dep[u] = dep[f] + 1, siz[u] = 1, fa[u] = f; for (int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].v; if (v == f) continue ; dfs(v, u), siz[u] += siz[v]; if (siz[son[u]] < siz[v]) son[u] = v; } } void dfs(int u, int f, int topf) { top[u] = topf, dfn[u] = ++dfn[0]; if (son[u]) dfs(son[u], u, topf); for (int i = head[u]; i; i = edge[i].nxt) { int v = edge[i].v; if (v == f || v == son[u]) continue ; dfs(v, u, v); } } void Update(int x) { int fx = top[x]; while (fx != 1) update(dfn[fx], dfn[x], 1), x = fa[fx], fx = top[x]; update(1, dfn[x], 1); } int Query(int x) { int fx = top[x], res = 0; while (fx != 1) res = (res + query(dfn[fx], dfn[x])) % mod, x = fa[fx], fx = top[x]; return (res + query(1, dfn[x])) % mod; } int main() { #ifndef ONLINE_JUDGE freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout); #endif read(n), read(q); for (int x, i = 2; i <= n; ++i) read(x), ++x, Add_edge(x, i), Add_edge(i, x); dfs(1, 0), dfs(1, 0, 1); for (int l, r, x, i = 1; i <= q; ++i) { read(l), ++l, read(r), ++r, read(x), ++x; t[++cnt] = (node) { r, x, 1, i }; t[++cnt] = (node) { l - 1, x, -1, i }; } sort(t + 1, t + cnt + 1, cmp); int p = 0; for (int i = 1; i <= cnt; ++i) { while (p < t[i].x) Update(++p); ans[t[i].id] = (ans[t[i].id] + t[i].opt * Query(t[i].y) + mod) % mod; } for (int i = 1; i <= q; ++i) printf("%d\n", ans[i]); return 0; }
posted @   Sangber  阅读(237)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
历史上的今天:
2019-06-14 「NOIP2009」Hankson的趣味题
点击右上角即可分享
微信分享提示