首先每个点可以更新的点的最短路都是 d i s [ i ] + c o s [ i ] dis[i]+cos[i] dis[i]+cos[i],所以维护一个堆,按排序,这样每个节点只会被修改一次
那么如何快速找出所有没有更新的点呢,我们考虑点分树
从每个重心开始bfs,然后用队列记录下所遍历到的每个点,这显然总共只有 n l o g n nlogn nlogn个节点
查找没修改过的点,对于子树内的点,可以直接删队列内的点,对于子树外的点,可以找点分树父亲的队列进行修改
每次最多爬 l o g log log的父亲, 总共只会删 n l o g n nlogn nlogn个节点
复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
开系统队列直接炸内存了,只好手写了一个
#include
#include
#include
using namespace std;
#define dd c=getchar()
int read() {int s=0,w=1;char c;while (dd,c>'9' || c<'0') if (c=='-') w=-1;while (c>='0' && c<='9') s=s*10+c-'0',dd;return s*w;}
#undef dd
void write(int x) {if (x<0) putchar('-'),x=-x;if (x>=10) write(x/10);putchar(x%10|'0');}
void wln(int x) {write(x);putchar('\n');}void wsp(int x) {write(x);putchar(' ');}
#define ll long long
const int N = 3e5+7;
struct edge {
int t,nxt;
}e[N<<1];
int n,S,cnt,T;
int head[N],lim[N],vis[N],dfn[N],pos[N],dep[N],lg[N<<1],mn[N<<1][20];
ll dis[N],cos[N];
struct cmp {
bool operator () (int a, int b) const {
return dis[a] + cos[a] > dis[b] + cos[b];
}
};
priority_queue<int,vector<int>, cmp> q;
void add(int u, int t) {
e[++cnt] = (edge) {t,head[u]}; head[u] = cnt;
}
void dfs(int u, int F) {
dep[u] = dep[F] + 1;
pos[u] = ++T; mn[T][0] = u;
for (int i = head[u]; i; i = e[i].nxt) {
int t = e[i].t;
if (t == F) continue;
dfs(t, u);
mn[++T][0] = u;
}
}
int lca(int x, int y) {
x = pos[x]; y = pos[y];
if (x > y) swap(x, y);
int t = lg[y-x+1];
return dep[mn[x][t]] < dep[mn[y-(1<<t)+1][t]] ? mn[x][t] : mn[y-(1<<t)+1][t];
}
int dist(int x, int y) {
return dep[x] + dep[y] - 2 * dep[lca(x, y)];
}
//==================================================
int Sz,rt,mx;
int siz[N],F[N],flg[N],in[N];
void getroot(int x, int f) {
siz[x] = 1;
int Bs=0;
for (int i = head[x]; i; i = e[i].nxt) {
int t = e[i].t;
if (t == f || vis[t]) continue;
getroot(t, x);
siz[x] += siz[t];
Bs = max(Bs, siz[t]);
}
Bs = max(Bs, Sz - siz[x]);
if (Bs < mx) mx = Bs, rt = x;
}
#define pii pair
#define mk make_pair
#define fi first
#define se second
queue<pii> Q;
int h[N],nxt[N*30];
int Cnt,tp;
pii son[N*30],st[N];
void Add(int u, pii now) {
son[++Cnt] = now; nxt[Cnt] = h[u]; h[u] = Cnt;
}
void bfs(int x) {
Q.push(mk(0, x));
in[x] = x;
while (!Q.empty()) {
pii now = Q.front(); Q.pop();
st[++tp] = now;
int u = now.se, dep = now.fi;
for (int i = head[u]; i; i = e[i].nxt) {
int t = e[i].t;
if (in[t] == x || vis[t]) continue;
in[t] = x;
Q.push(mk(dep+1, t));
}
}
while (tp) Add(x, st[tp--]);
// printf("%d\n",son[x].size());
}
void divide(int x) {
vis[x] = 1;
// for (int i = head[x]; i; i = e[i].nxt) if (!vis[e[i].t])
bfs(x);
for (int i = head[x]; i; i = e[i].nxt) {
int t = e[i].t;
if (vis[t]) continue;
Sz = siz[t]; mx = 1e9;
getroot(t, x);
F[rt] = x;
divide(rt);
}
}
void delet(int x, int limit, ll v, int u) {
if (lim < 0) return;
while (h[x] && son[h[x]].fi <= limit) {
int k = son[h[x]].se; h[x] = nxt[h[x]];
if (flg[k]) continue;
dis[k] = v, flg[k] = 1, q.push(k);
}
if (F[x]) delet(F[x], lim[u] - dist(u, F[x]), v, u);
}
int main() {
// freopen("5129.in", "r", stdin);
// freopen("5129.out", "w", stdout);
n = read(); S = read();
for (int i = 1, u, v; i < n; i++) {
u = read(), v = read();
add(u, v); add(v, u);
}
for (int i = 1; i <= n; i++) lim[i] = read(), cos[i] = read();
dfs(1, 0); // get dis
for (int i = 2; i <= T; i++) lg[i] = lg[i>>1] + 1;
for (int i = 1; i <= 19; i++)
for (int j = 1; j+(1<<i) <= T; j++)
mn[j][i] = dep[mn[j][i-1]] < dep[mn[j+(1<<i-1)][i-1]] ? mn[j][i-1] : mn[j+(1<<i-1)][i-1];
Sz = n; mx = 1e9;
getroot(1, 0);
divide(rt); // get divide tree
dis[S] = 0; flg[S] = 1;
q.push(S);
while (!q.empty()) {
int u = q.top(); q.pop();
delet(u, lim[u], dis[u] + cos[u], u);
}
for (int i = 1; i <= n; i++) printf("%lld\n",dis[i]);
}