51Nod-1681-公共祖先
2017-07-10 19:40
295 查看
ACM模版
贴一下官方题解吧:
貌似,这里用树状数组维护也是可以的啊……当然,我并不会。水平太臭了!
描述
题解
第一次接触主席树,感觉好叼好叼,无法驾驭它啊~~~贴一下官方题解吧:
貌似,这里用树状数组维护也是可以的啊……当然,我并不会。水平太臭了!
代码
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN = 1e5 + 10; const int MAXM = 2e6 + 10; int n, tot, sz; int LS[MAXN], RS[MAXN]; // LS[i]: L 树的 i 结点的 dfs 序的起点 RS[i]: 同理 int LE[MAXN], RE[MAXN]; // LE[i]: L 树的 i 结点的 dfs 序的终点 RE[i]: 同理 int tmp[MAXN]; // tmp[i]: R 树中 dfs 序为 i 的结点 u 在 L 树 dfs 序中对应的位置 int pos[MAXN]; // pos[i]: L 树中 i 结点的 dfs 序的位置 int vis[MAXN]; int head[MAXN]; int root[MAXN]; struct node { int l, r, c; } tree[MAXM]; struct Edge { int to, nt; } e[MAXN]; void init() { tot = 0; memset(head, -1, sizeof(head)); memset(vis, 0, sizeof(vis)); } void addedge(int u, int v) { e[tot].to = v; e[tot].nt = head[u]; head[u] = tot++; } void dfs(int u, int pre, int flag) { if (flag) { RS[u] = ++sz; tmp[sz] = pos[u]; } else { LS[u] = ++sz; pos[u] = sz; } int v; for (int i = head[u]; i != -1; i = e[i].nt) { v = e[i].to; if (v != pre) { dfs(v, u, flag); } } if (flag) { RE[u] = sz; } else { LE[u] = sz; } } template <class T> inline void scan_d(T &ret) { char c; ret = 0; while ((c = getchar()) < '0' || c > '9'); while (c >= '0' && c <= '9') { ret = ret * 10 + (c - '0'), c = getchar(); } } void update(int &rt, int l, int r, int num) { tree[++sz] = tree[rt]; rt = sz; tree[rt].c++; if (l == r) { return ; } int mid = (l + r) >> 1; if (num <= mid) { update(tree[rt].l, l, mid, num); } else { update(tree[rt].r, mid + 1, r, num); } } int query(int x, int y, int L, int R, int l, int r) { if (L <= l && R >= r) { return tree[y].c - tree[x].c; } int m = (l + r) >> 1; int ret = 0; if (L <= m) { ret += query(tree[x].l, tree[y].l, L, R, l, m); } if (R > m) { ret += query(tree[x].r, tree[y].r, L, R, m + 1, r); } return ret; } int main() { scan_d(n); int u, v, r = 0; init(); for (int i = 1; i < n; i++) { scan_d(u), scan_d(v); addedge(u, v); vis[v] = 1; } sz = 0; for (int i = 1; i <= n; i++) { if (vis[i] == 0) { r = i; break; } } dfs(r, 0, 0); init(); for (int i = 1; i < n; i++) { scan_d(u), scan_d(v); addedge(u, v); vis[v] = 1; } sz = 0; for (int i = 1; i <= n; i++) { if (vis[i] == 0) { r = i; break; } } dfs(r, 0, 1); root[0] = 0, sz = 0; for (int i = 1; i <= n; i++) { root[i] = root[i - 1]; update(root[i], 1, n, tmp[i]); } long long ans = 0; for (int i = 1; i <= n; i++) { int x = query(root[RS[i] - 1], root[RE[i]], LS[i], LE[i], 1, n); ans += 1LL * (x - 1) * (x - 2) / 2; } printf("%lld\n",ans); return 0; }
参考
《主席树》相关文章推荐
- 51nod 1681 公共祖先
- 【DFS序+树状数组】51Nod 1681 公共祖先
- 51Nod 1681 公共祖先 [主席树做法]
- 51nod 1681 公共祖先【树状数组】【DFS序】
- 51Nod 1681 公共祖先 [树状数组做法]
- 51nod 1681 公共祖先 | 树状数组
- 51nod 1681 公共祖先 主席树dfs序
- 51nod 1681 公共祖先 (在这两个平行宇宙有多少人一直是他们的公共祖先)
- 1681 公共祖先
- 51nod:公共祖先(主席树 & DFS序)
- 51 nod 1681 公共祖先 (主席树+dfs序)
- LCA(最近公共祖先 Tarjan) CodeVs-2370-小机房的树
- LCA(最近公共祖先)
- [转]Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)
- 树中两个结点的最低公共祖先
- 最近公共祖先(板子)
- 最近公共祖先
- 最近公共祖先LCA:RMQ转化
- 最近公共祖先LCA tarjan
- [HihoCoder]#1067 : 最近公共祖先·二