求前M个路径,使路径权最小。
和NOI 2010 超级钢琴类似。。。
#include <queue>
#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int N = 50005, M = N * 2, S = 2000005;
using namespace std;
int bin[20], lb[N];
int f[N], sz[N], dis[N], sum, rt;
int sk[S], top, mx[S][20];
pair<int, int> pa[S];
bool vis[N];
int h[N], p[M], v[M], w[M], cnt, n;
void init_rmq(int n) {
int i, j, t1, t2;
bin[0] = 1; FOR(i,1,19) bin[i] = bin[i - 1] << 1;
lb[0] = -1; FOR(i,1,n) lb[i] = lb[i >> 1] + 1;
FOR(i,1,top) mx[i][0] = i;
FOR(i,1,lb[n]) FOR(j,1,top) if(j + bin[i] <= top) {
t1 = mx[j][i - 1], t2 = mx[j + bin[i - 1]][i - 1];
mx[j][i] = sk[t1] > sk[t2] ? t1 : t2;
}
}
int query(int l, int r) {
if (l == r) return l;
int t = lb[r - l + 1];
int t1 = mx[l][t], t2 = mx[r - bin[t] + 1][t];
return sk[t1] > sk[t2] ? t1 : t2;
}
struct Data { int x, l, r, t;
Data(int a,int b,int c):l(a),r(b),x(c),t(query(a,b)){}
};
priority_queue<Node> q;
bool operator< (Data a, Data b) {
return sk[a.t] + sk[a.x] < sk[b.t] + sk[b.x];
}
void add(int a, int b, int c) {
v[++cnt] = b; p[cnt] = h[a]; w[cnt] = c; h[a] = cnt;
}
void root(int x, int fa) {
f[x] = 0; sz[x] = 1;
for (int i = h[x]; i; i = p[i])
if (v[i] != fa && !vis[v[i]]) {
root(v[i], x);
sz[x] += sz[v[i]];
f[x] = max(f[x], sz[v[i]]);
}
f[x] = max(f[x], sum - sz[x]);
if (f[x] < f[rt]) rt = x;
}
int get_root(int x, int fa, int sz) {
rt = 0; sum = sz; f[0] = sz + 1;
root(x, fa); return rt;
}
void depth(int x, int fa, int l, int r) {
sk[++top] = dis[x]; pa[top] = make_pair(l, r);
for (int i = h[x]; i; i = p[i])
if (v[i] != fa && !vis[v[i]]) {
dis[v[i]] = dis[x] + w[i];
depth(v[i], x, l, r);
}
}
void solve(int x) {
int l, r, i;
sk[++top] = 0; pa[top] = make_pair(0, 0);
vis[x] = 1; l = r = top;
for (i = h[x]; i; i = p[i])
if (!vis[v[i]]) {
dis[v[i]] = w[i];
depth(v[i], x, l, r);
r = top;
}
for (i = h[x]; i; i = p[i])
if (!vis[v[i]])
solve(get_root(v[i], x, sz[v[i]]));
}
int main() {
int i, a, b, c, m;
scanf("%d%d", &n, &m);
FOR(i,2,n) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c); add(b, a, c);
}
solve(get_root(1, 0, n));
init_rmq(n);
FOR(i,1,top) if (pa[i].first)
q.push(Data(pa[i].first, pa[i].second, i));
while (m--) {
Node t = q.top(); q.pop();
printf("%d\n", sk[t.mx] + sk[t.x]);
if (t.t < t.r) q.push(Data(t.t + 1, t.r, t.x));
if (t.t > t.l) q.push(Data(t.l, t.t - 1, t.x));
}
return 0;
}
树上的路径
Description
给定一个N个结点的树,结点用正整数1..N编号。每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路边上经过边的权值。其中要求a
Output
共M行,如题所述.
Sample Input
5 10
1 2 1
1 3 2
2 4 3
2 5 4
Sample Output
7
7
6
5
4
4
3
3
2
1
HINT
N<=50000,M<=Min(300000,n*(n-1) /2 )