虚树
板题,基本上是对着网上的板子敲的
#include <bits/stdc++.h> using namespace std; inline int read() { int out = 0; register char cc = getchar(); while (cc < '0' || cc > '9') cc = getchar(); while (cc >= '0' && cc <= '9') out = (out << 3) + (out << 1) + (cc ^ 48), cc = getchar(); return out; } inline void write(long long x) { if (x == 0) putchar('0'); else { int num = 0; char c[20]; while (x) c[++num] = x % 10 + 48, x /= 10; while (num) putchar(c[num--]); } putchar(' '); } int N, M, K, a, b, c, Id[500010]; int head[500010], nxt[1000010], to[1000010], edge[1000010], cnt; void add_edge(int u, int v, int w) { to[++cnt] = v; edge[cnt] = w; nxt[cnt] = head[u]; head[u] = cnt; } void add(int u, int v) { to[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt; } int dfn[500010], tim; int f[500010][19], dep[500010]; long long Min[500010]; void dfs(int u, int fa) { dep[u] = dep[fa] + 1; f[u][0] = fa; dfn[u] = ++tim; for (int i = 1; i < 19; i++) f[u][i] = f[f[u][i - 1]][i - 1]; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; Min[v] = (Min[u] < edge[i] ? Min[u] : edge[i]); dfs(v, u); } } int Lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (int i = 18; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } inline bool cmp(const int &g, const int &h) { return dfn[g] < dfn[h]; } int Stack[500010], tot; void Insert(int x) { if (tot == 1) { Stack[++tot] = x; return ; } int lca = Lca(x, Stack[tot]); if (lca == Stack[tot]) return ; while (tot > 1 && dfn[lca] <= dfn[Stack[tot - 1]]) add(Stack[tot - 1], Stack[tot]), tot--; if (lca != Stack[tot]) add(lca, Stack[tot]), Stack[tot] = lca; Stack[++tot] = x; } long long dp(int u) { long long ans = 0; for (int i = head[u]; i; i = nxt[i]) ans = ans + dp(to[i]); if (ans == 0) ans = 1LL << 60; head[u] = 0; return min(ans, Min[u]); } int main() { N = read(); for (int i = 1; i < N; i++) { a = read(), b = read(), c = read(); add_edge(a, b, c); add_edge(b, a, c); } Min[1] = 1LL << 60; dfs(1, 0); memset(head, 0, sizeof(head)); for (M = read(); M; M--) { K = read(), cnt = 0; for (int i = 1; i <= K; i++) Id[i] = read(); sort(Id + 1, Id + K + 1, cmp); Stack[tot = 1] = 1; for (int i = 1; i <= K; i++) Insert(Id[i]); while (tot) add(Stack[tot - 1], Stack[tot]), tot--; write(dp(1)); } return 0; }
虚树+树形DP+倍增
每次把议事处构成的虚树先建出来 $Theta(sum m_i log n)$
然后换根DP,求到每个虚树上的点的最近议事处 $Theta(sum m_i)$ (ps:你要多源最短路也行,慢一点)
最后对每条虚树上的边(实际在原树中为一条链),直接算出分界点(链上哪些属于上端,哪些属于下端),从下端点到上端点倍增即可 $Theta(sum m_i log n)$
思路挺简单的,细节对蒟蒻来说有一点点多
#include <bits/stdc++.h> using namespace std; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(int x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } const int N = 3e5 + 10; int n, m, id[N], Id[N], ans[N]; int head[N], to[N << 1], nxt[N << 1], cnt; void add_edge(int u, int v) { to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt; } int dep[N], f[N][19], dfn[N], times, sze[N], s[N][19]; void dfs(int u, int fa) { dep[u] = dep[fa] + 1, f[u][0] = fa, dfn[u] = ++times; for (int i = 1; i <= 18; i++) f[u][i] = f[f[u][i - 1]][i - 1]; sze[u] = 1; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; dfs(v, u), sze[u] += sze[v]; } for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; s[v][0] = sze[u] - sze[v]; } } void count(int u, int fa) { for (int i = 1; i <= 18; i++) s[u][i] = s[u][i - 1] + s[f[u][i - 1]][i - 1]; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; count(v, u); } } inline bool cmp(const int &g, const int &h) { return dfn[g] < dfn[h]; } int stk[N], tp, cl[N], tot; bool vis[N]; vector<int> son[N]; int Lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (int i = 18; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } void ins(int x) { if (tp <= 1) return cl[++tot] = stk[++tp] = x, void(); int lca = Lca(x, stk[tp]); if (lca != stk[tp]) { while (tp > 1 && dfn[lca] <= dfn[stk[tp - 1]]) son[stk[tp - 1]].push_back(stk[tp]), tp--; if (lca != stk[tp]) son[lca].push_back(stk[tp]), cl[++tot] = stk[tp] = lca; } cl[++tot] = stk[++tp] = x; } int up[N], upid[N]; void pre(int u) { //cout << u << " "; if (vis[u]) up[u] = 0, upid[u] = u; else up[u] = 0x3f3f3f3f, upid[u] = 0x3f3f3f3f; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; pre(v); if (up[u] > up[v] + dep[v] - dep[u] || (up[u] == up[v] + dep[v] - dep[u] && upid[u] > upid[v])) up[u] = up[v] + dep[v] - dep[u], upid[u] = upid[v]; } } int Min[N], Minid[N]; void dp(int u) { if (vis[u]) Min[u] = 0, Minid[u] = u; int fi = Min[u], se = 0x3f3f3f3f, fiid = Minid[u], seid = 0x3f3f3f3f; if (vis[u]) fi = 0, fiid = u; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; if (fi > up[v] + dep[v] - dep[u] || (fi == up[v] + dep[v] - dep[u] && fiid > upid[v])) se = fi, seid = fiid, fi = up[v] + dep[v] - dep[u], fiid = upid[v]; else if (se > up[v] + dep[v] - dep[u] || (se == up[v] + dep[v] - dep[u] && seid > upid[v])) se = up[v] + dep[v] - dep[u], seid = upid[v]; } Min[u] = fi, Minid[u] = fiid; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; if (up[v] + dep[v] - dep[u] == fi && upid[v] == fiid) Min[v] = se + dep[v] - dep[u], Minid[v] = seid; else Min[v] = fi + dep[v] - dep[u], Minid[v] = fiid; dp(v); } } int get(int u, int k) { int res = 0; for (int i = 18; i >= 0; i--) if (k >= (1 << i)) k -= (1 << i), res += s[u][i], u = f[u][i]; return res; } void calc(int u) { int sum = sze[u]; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; calc(v); int k = dep[v] - dep[u] + Min[u] - Min[v]; int now = get(v, (k & 1) ? (k >> 1) : ((k >> 1) - (Minid[u] < Minid[v]))); sum -= (now + sze[v]), ans[Minid[v]] += now; } ans[Minid[u]] += sum; } int main() { n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); add_edge(u, v), add_edge(v, u); } dfs(1, 0), count(1, 0); for (int T = read(); T; T--) { for (int i = 1; i <= tot; i++) son[cl[i]].clear(); for (int i = 1; i <= m; i++) vis[id[i]] = false; m = read(); for (int i = 1; i <= m; i++) vis[Id[i] = id[i] = read()] = true, ans[Id[i]] = 0; sort(id + 1, id + m + 1, cmp); tot = tp = 0; if (id[1] != 1) cl[tot = 1] = stk[tp = 1] = 1; for (int i = 1; i <= m; i++) ins(id[i]); while (tp > 1) son[stk[tp - 1]].push_back(stk[tp]), tp--; Min[1] = Minid[1] = 0x3f3f3f3f, pre(1), dp(1); calc(1); for (int i = 1; i <= m; i++) write(ans[Id[i]], ' '); putchar(' '); } return 0; }
圆方树
建完圆方树,把圆点点权设$1$,方点设为$0$,点权存在点的父亲边上
按$dfs$序每次询问的点排序,每对相邻的点求距离,然后加减其它几个多算没算的值
#include <bits/stdc++.h> using namespace std; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(int x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } const int N = 1e5 + 10, M = 2e5 + 10; int n, m, k, a[N], nodeid; int head[N], to[M << 1], nxt[M << 1], cnt; void add_edge(int u, int v) { to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt; } int dfn[N << 1], low[N], times, stk[N], tp; vector<int> son[N << 1]; int fa[N << 1][18], dep[N << 1], dis[N << 1]; void tarjan(int u) { dfn[u] = low[u] = ++times, stk[++tp] = u; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (!dfn[v]) { tarjan(v); if (low[u] > low[v]) low[u] = low[v]; if (dfn[u] == low[v]) { ++nodeid; for (int p = 0; p != v; tp--) { p = stk[tp]; son[nodeid].push_back(p); } son[u].push_back(nodeid); } } else if (low[u] > dfn[v]) low[u] = dfn[v]; } } void dfs(int u) { dfn[u] = ++times; for (int i = 1; i <= 17; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; dep[v] = dep[u] + 1, fa[v][0] = u, dis[v] = dis[u] + (v <= n), dfs(v); } } int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (int i = 17; i >= 0; i--) if (dep[fa[x][i]] >= dep[y]) x = fa[x][i]; if (x == y) return x; for (int i = 17; i >= 0; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; return fa[x][0]; } inline bool cmp(const int &g, const int &h) { return dfn[g] < dfn[h]; } int main() { for (int T = read(); T; T--) { n = read(), m = read(), cnt = 0; for (int i = 1; i <= n; i++) head[i] = 0, dfn[i] = low[i] = 0; for (int i = 1; i <= m; i++) { int u = read(), v = read(); add_edge(u, v), add_edge(v, u); } for (int i = 1; i <= nodeid; i++) son[i].clear(); nodeid = n, times = tp = 0, tarjan(1); times = 0, dfs(1); for (int q = read(); q; q--) { k = read(); for (int i = 1; i <= k; i++) a[i] = read(); sort(a + 1, a + k + 1, cmp); int ans = dis[a[1]] + dis[a[k]] - 2 * dis[lca(a[1], a[k])]; for (int i = 2; i <= k; i++) ans += dis[a[i - 1]] + dis[a[i]] - 2 * dis[lca(a[i - 1], a[i])]; ans = (ans >> 1) - k + (lca(a[1], a[k]) <= n); write(ans, ' '); } } return 0; }
动态树
树套树
平衡树
先将T恤按品质从大到小排,品质相同按价格从小到大排
暴力则是对于每个人,按顺序试遍每件T恤
优化则考虑对于每件T恤,有哪些人会买
具体是维护一个当前所有人所剩钱数组成的递增序列,二分出所剩钱数大于等于当前T恤的有哪些人(为该序列的一个后缀)
直接将一段区间平移并不好直接做(但好像可以可持久化平衡树??还不是很懂哇)
这题的平移只有向钱数少的方向平移
假设当前T恤价格为$c_i$
考虑把序列分为三段$[1,c_i),[c_i,2 imes c_i),[2 imes c_i, k]$,第二段暴力单点修改,第三段区间打上$-c_i$的$tag$
发现每个人被暴力单点改的时候钱数会减少一半以上,最多被改$log$次
#include <bits/stdc++.h> using namespace std; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(int x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } const int N = 2e5 + 10; int n, k, nodeid, val[N], rd[N], cnt[N], ls[N], rs[N], rt, a, b, c, tag[N], g[N]; struct shirt { int c, q; void readdata() { c = read(), q = read(); } bool operator < (const shirt &g) const { if (q != g.q) return q > g.q; return c < g.c; } } t[N]; int newnode(int s) { ++nodeid, rd[nodeid] = rand(), val[nodeid] = s; return nodeid; } void dec(int u, int s, int r) { tag[u] += s, val[u] -= s, g[u] += r, cnt[u] += r; } void pushdown(int u) { if (tag[u] || g[u]) { if (ls[u]) dec(ls[u], tag[u], g[u]); if (rs[u]) dec(rs[u], tag[u], g[u]); tag[u] = g[u] = 0; } } void split(int u, int s, int &x, int &y) { if (!u) return x = y = 0, void(); pushdown(u); if (val[u] <= s) x = u, split(rs[u], s, rs[x], y); else y = u, split(ls[u], s, x, ls[y]); } int merge(int x, int y) { if (!x || !y) return x | y; if (rd[x] < rd[y]) return pushdown(x), rs[x] = merge(rs[x], y), x; else return pushdown(y), ls[y] = merge(x, ls[y]), y; } void dfs(int u) { pushdown(u); if (ls[u]) dfs(ls[u]); if (rs[u]) dfs(rs[u]); ls[u] = rs[u] = 0; int x, y; split(a, val[u], x, y), a = merge(merge(x, u), y); } void calc(int u) { pushdown(u); if (ls[u]) calc(ls[u]); if (rs[u]) calc(rs[u]); } int main() { n = read(); for (int i = 1; i <= n; i++) t[i].readdata(); sort(t + 1, t + n + 1); k = read(), rt = newnode(read()); for (int i = 2; i <= k; i++) { int s = read(); split(rt, s, a, b), rt = merge(merge(a, newnode(s)), b); } for (int i = 1; i <= n; i++) { split(rt, t[i].c - 1, a, b), dec(b, t[i].c, 1), split(b, t[i].c, b, c); dfs(b), rt = merge(a, c); } calc(rt); for (int i = 1; i <= k; i++) write(cnt[i], ' '); return 0; }
CDQ分治&整体二分
K-D tree
珂朵莉树
[CF896C]Willem, Chtholly and Seniorious
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline void write(ll x, char ch) { if (x < 0) putchar('-'), x = -x; if (x == 0) putchar('0'); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } inline ll fpow(ll x, ll y, ll Mod) { ll res = 1; x %= Mod; while (y) { if (y & 1) res = res * x % Mod; x = x * x % Mod; y >>= 1; } return res; } const int N = 1e5 + 10; int n, m, seed, vmax, tot; int rnd() { int ret = seed; seed = (seed * 7ll + 13) % 1000000007; return ret; } struct range { int l, r; mutable ll v; bool operator < (const range &g) const { return l < g.l; } } tmp[N]; inline bool cmp(const range &g, const range &h) { return g.v < h.v; } set<range> odt; set<range>::iterator split(int x) { if (x > n) return odt.end(); set<range>::iterator it = --odt.upper_bound(range{x, 0, 0}); if (it->l == x) return it; int l = it->l, r = it->r; ll v = it->v; odt.erase(it), odt.insert(range{l, x - 1, v}); return odt.insert(range{x, r, v}).first; } void assign(int l, int r, ll v) { set<range>::iterator itr = split(r + 1), itl = split(l); odt.erase(itl, itr), odt.insert(range{l, r, v}); } int main() { cin >> n >> m >> seed >> vmax; for (int i = 1; i <= n; i++) odt.insert(range{i, i, rnd() % vmax + 1}); //cout << endl; for (int i = 1; i <= m; i++) { int op = rnd() % 4 + 1, l = rnd() % n + 1, r = rnd() % n + 1, x, y = 0; if (l > r) swap(l, r); if (op == 3) x = rnd() % (r - l + 1) + 1; else x = rnd() % vmax + 1; if (op == 4) y = rnd() % vmax + 1; //cout << op << ' ' << l << " " << r << " " << x << " " << y << endl; if (op == 1) { set<range>::iterator itr = split(r + 1), itl = split(l); while (itl != itr) itl->v += x, itl++; } else if (op == 2) assign(l, r, x); else if (op == 3) { set<range>::iterator itr = split(r + 1), itl = split(l); tot = 0; while (itl != itr) tmp[++tot] = (*itl), itl++; sort(tmp + 1, tmp + tot + 1, cmp); for (int i = 1; i <= tot; i++) { x -= (tmp[i].r - tmp[i].l + 1); if (x <= 0) { write(tmp[i].v, ' '); break; } } } else { set<range>::iterator itr = split(r + 1), itl = split(l); int ans = 0; while (itl != itr) ans = (ans + fpow(itl->v, x, y) * (itl->r - itl->l + 1)) % y, itl++; write(ans, ' '); } } return 0; }
线段树合并
#include <bits/stdc++.h> #define Mod 998244353 using namespace std; typedef long long ll; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } const int N = 5e5 + 10; int n, m, dep[N], g[N]; ll a, b; int head[N], to[N << 1], nxt[N << 1], cnt; void add_edge(int u, int v) { to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt; } void dfs(int u, int fa) { dep[u] = dep[fa] + 1; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; dfs(v, u); } } int ls[N << 5], rs[N << 5], sum[N << 5], mul[N << 5], rt[N], nodeid; void pushdown(int u) { if (ls[u]) { sum[ls[u]] = 1ll * sum[ls[u]] * mul[u] % Mod; mul[ls[u]] = 1ll * mul[ls[u]] * mul[u] % Mod; } if (rs[u]) { sum[rs[u]] = 1ll * sum[rs[u]] * mul[u] % Mod; mul[rs[u]] = 1ll * mul[rs[u]] * mul[u] % Mod; } mul[u] = 1; } void modify(int &u, int l, int r, int pos) { u = ++nodeid, mul[u] = sum[u] = 1; if (l == r) return ; int mid = (l + r) >> 1; if (pos <= mid) modify(ls[u], l, mid, pos); else modify(rs[u], mid + 1, r, pos); } int query(int u, int l, int r, int Right) { if (r <= Right) return sum[u]; pushdown(u); int mid = (l + r) >> 1, res = 0; res += query(ls[u], l, mid, Right); if (res >= Mod) res -= Mod; if (mid < Right && rs[u]) { res += query(rs[u], mid + 1, r, Right); if (res >= Mod) res -= Mod; } return res; } int merge(int x, int y, int l, int r) { if (!x && !y) return 0; if (!x) { a += sum[y]; if (a >= Mod) a -= Mod; mul[y] = 1ll * mul[y] * b % Mod, sum[y] = 1ll * sum[y] * b % Mod; return y; } if (!y) { b += sum[x]; if (b >= Mod) b -= Mod; mul[x] = 1ll * mul[x] * a % Mod, sum[x] = 1ll * sum[x] * a % Mod; return x; } if (l == r) { ll p = sum[x], q = sum[y]; a += q; if (a >= Mod) a -= Mod; sum[x] = (sum[x] * a + sum[y] * b) % Mod; b += p; if (b >= Mod) b -= Mod; return x; } pushdown(x), pushdown(y); int mid = (l + r) >> 1; ls[x] = merge(ls[x], ls[y], l, mid); rs[x] = merge(rs[x], rs[y], mid + 1, r); sum[x] = sum[ls[x]] + sum[rs[x]]; if (sum[x] >= Mod) sum[x] -= Mod; return x; } void calc(int u, int fa) { modify(rt[u], 0, n, g[u]); for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; calc(v, u); a = query(rt[v], 0, n, dep[u]), b = 0; rt[u] = merge(rt[u], rt[v], 0, n); } } int main() { n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); add_edge(u, v), add_edge(v, u); } dfs(1, 0); m = read(); for (int i = 1; i <= m; i++) { int u = read(), v = read(); if (g[v] < dep[u]) g[v] = dep[u]; } calc(1, 0); cout << query(rt[1], 0, n, 0) << endl; return 0; }
长链剖分
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < '0' || cc > '9') { if (cc == '-') flag = true; cc = getchar(); } while (cc >= '0' && cc <= '9') { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } const int N = 1e5 + 10; int n, head[N], to[N << 1], nxt[N << 1], cnt; void add_edge(int u, int v) { to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt; } int len[N], hea[N]; void dfs(int u, int fa) { for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; dfs(v, u); if (len[hea[u]] < len[v]) hea[u] = v; } len[u] = len[hea[u]] + 1; } ll tmp[N * 3], *id = tmp, *f[N], *g[N], ans; void calc(int u, int fa) { if (hea[u]) f[hea[u]] = f[u] + 1, g[hea[u]] = g[u] - 1, calc(hea[u], u); f[u][0] = 1, ans += g[u][0]; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa || v == hea[u]) continue; f[v] = id, id += len[v]; id += len[v], g[v] = id, id += len[v]; calc(v, u); for (int j = 0; j < len[v]; j++) { ans += f[v][j] * g[u][j + 1]; if (j) ans += g[v][j] * f[u][j - 1]; } for (int j = 0; j < len[v]; j++) { g[u][j + 1] += f[u][j + 1] * f[v][j]; if (j) g[u][j - 1] += g[v][j]; f[u][j + 1] += f[v][j]; } } } int main() { n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); add_edge(u, v), add_edge(v, u); } dfs(1, 0); f[1] = id, id += len[1]; id += len[1], g[1] = id, id += len[1]; calc(1, 0); cout << ans << endl; return 0; }