bzoj3784 树上的路径
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3784
【题解】
和超级钢琴很像啊。
一看题目,无脑点分。
那么我们发现点分的路径形式和“超级钢琴”的哪个很像啊。
点分是子树合并对吧,当前子树内的每个点都能选择前面子树的区间,那么跟“超级钢琴”不同的就是这个是加的。
那么点分治维护即可。距离似乎(?)不会太多,那么我们套用那个堆的做法就行。
upd:距离最多nlogn个。
# include <queue> # include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 1e6 + 10; const int mod = 1e9+7; # define RG register int n, m; int head[M], nxt[M], to[M], tot=0, w[M]; inline void add(int u, int v, int _w) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; w[tot] = _w; } inline void adde(int u, int v, int _w) { add(u, v, _w), add(v, u, _w); } int val[N], L[N], R[N], tn = 0; namespace DFZ { bool vis[M]; int sz[M], mx[M]; inline void getsize(int x, int fa=0) { sz[x] = 1, mx[x] = 0; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == fa || vis[to[i]]) continue; getsize(to[i], x); sz[x] += sz[to[i]]; if(sz[to[i]] > mx[x]) mx[x] = sz[to[i]]; } } int mi, centre; inline void getcentre(int x, int tp, int fa=0) { if(sz[tp] - sz[x] > mx[x]) mx[x] = sz[tp] - sz[x]; if(mx[x] < mi) mi = mx[x], centre = x; for (int i=head[x]; i; i=nxt[i]) { if(to[i] == fa || vis[to[i]]) continue; getcentre(to[i], tp, x); } } int curl, curr; inline void calc(int x, int fa, int dis) { val[++tn] = dis, L[tn] = curl, R[tn] = curr; for (int i=head[x]; i; i=nxt[i]) if(to[i] != fa && !vis[to[i]]) calc(to[i], x, dis+w[i]); } inline void dfs(int x) { getsize(x); mi=n; getcentre(x, x); x = centre; ++tn; curl = curr = tn; for (int i=head[x]; i; i=nxt[i]) if(!vis[to[i]]) calc(to[i], x, w[i]), curr = tn; vis[x] = 1; for (int i=head[x]; i; i=nxt[i]) if(!vis[to[i]]) dfs(to[i]); } } namespace ST { struct rmq { int i, v; rmq() {} rmq(int i, int v) : i(i), v(v) {} friend bool operator <(rmq a, rmq b) { return a.v<b.v; } friend bool operator >(rmq a, rmq b) { return a.v>b.v; } }; int n, Log2[N]; rmq f[N][21]; inline void init(int _n) { n = _n; Log2[1] = 0; for (int i=2; i<=n; ++i) Log2[i] = Log2[i>>1] + 1; for (int i=1; i<=n; ++i) f[i][0] = rmq(i, val[i]); for (int j=1; j<=20; ++j) for (int i=1; i+(1<<j)-1<=n; ++i) f[i][j] = max(f[i][j-1], f[i+(1<<(j-1))][j-1]); } inline bool getpos(int l, int r, int &i, int &v) { if(l > r) return 0; int len = Log2[r-l+1]; rmq t = max(f[l][len], f[r-(1<<len)+1][len]); i = t.i, v = t.v; return 1; } } struct pa { int x, l, r, mx, v; pa() {} pa(int x, int l, int r, int mx, int v) : x(x), l(l), r(r), mx(mx), v(v) {} friend bool operator < (pa a, pa b) { return a.v<b.v; } }; priority_queue<pa> q; int main() { scanf("%d%d", &n, &m); for (int i=1, u, v, _w; i<n; ++i) { scanf("%d%d%d", &u, &v, &_w); adde(u, v, _w); } DFZ::dfs(1); ST::init(tn); while(!q.empty()) q.pop(); for (int i=1; i<=tn; ++i) { int va, po; ST::getpos(L[i], R[i], po, va); q.push(pa(i, L[i], R[i], po, va+val[i])); } for (int i=1; i<=m; ++i) { pa t = q.top(); printf("%d\n", t.v); q.pop(); int va, po; if(ST::getpos(t.l, t.mx-1, po, va)) q.push(pa(t.x, t.l, t.mx-1, po, val[t.x]+va)); if(ST::getpos(t.mx+1, t.r, po, va)) q.push(pa(t.x, t.mx+1, t.r, po, val[t.x]+va)); } return 0; }