显然,一棵树的带权重心最多只有两个,最少会有一个,而且在这两个点的答案一定相等。(都是带权重心当然相等)鉴于点分治的写法貌似并不太需要这样的分析,就不说了。我不会
首先建出一颗点分树,然后考虑在点分树上跳儿子来保证复杂度,于是我们就需要快速算出所有点到这个重心的带权距离和。由于这题是点分树,考虑在点分树上维护一些信息来快速计算这个东西。
对于我们当前枚举到的这个点\(x\),一部分答案贡献来自点分树上\(x\)的子树以内,这部分可以直接记录一个\(dsum[x]\)表示在点分树上\(x\)的子树内的所有点到\(x\)的距离和。另一部分来自子树外,我们先只考虑\(x\)在点分树上的父节点\(fa[x]\)的子树里的点对这里的贡献,至于\(fa[fa[x]]\)可以以此类推。那么这个贡献就又分为两部分,一部分是\(fa[x]\)的子树内根不为\(x\)的子树内的点到\(fa[x]\)的距离。这个时候显然如果直接使用\(dsum[fa[x]]\)会导致重复计算,所以要记录一个\(fsum[x]\)来表示\(x\)这个子树内的所有点到\(fa[x]\)的距离和。那么这一部分的答案贡献就是\(dsum[fa[x]]-fsum[x]\)。那么还有一部分的答案就是这些点都到了\(fa[x]\)之后再到\(x\)的距离和,那这部分的答案就是\(dis(fa[x],x)\times(ssum[fa[x]]-ssum[x])\)。这里的\(ssum[x]\)就是\(x\)子树内的\(size\)之和。\(dis\)的处理也需要树剖来维护。然后向上爬点分树的时候注意一下,哪些地方应该用原始的\(x\),哪些地方应该用向上跳了的结点就可以了。具体的实现在代码里。时间复杂度是\(O(nlogn^3)\),由于树剖常数小,可以跑过。
然后我写的时候有一个想法,在于为什么不能直接维护一个点和根的关系呢?这样不就\(O(1)\)了吗?后来想想发现,我们的算法是基于外部的点要到\(x\)必须要经过\(x\)在点分树上的祖先才能够做到枚举的。这点要想通我个人认为还是很重要的。
upd:一个要注意的一点是在求答案的时候要在原树上找儿子,在点分树上跳重心。

#include <cstdio>
using namespace std;
#define R register
#define LL long long
const int MAXN=5e5+10;
inline int read() {
	int x=0,f=1; char a=getchar();
	for(;a>'9'||a<'0';a=getchar()) if(a=='-') f=-1;
	for(;a>='0'&&a<='9';a=getchar()) x=x*10+a-'0';
	return x*f;
}
inline int max(int x,int y) { return x > y ? x : y; }
inline int min(int x,int y) { return x < y ? x : y; }
int n,q;
namespace Graph {
	int cnt,head[MAXN];
	struct edge { int to,w,next; } e[MAXN<<1];
	inline void add(int x,int y,int w) {
		e[++cnt]={y,w,head[x]}; head[x]=cnt; 
	}
	int dep[MAXN],dis[MAXN],fa[MAXN],son[MAXN],siz[MAXN],top[MAXN];
	inline void dfs1(int x,int fx) {
		fa[x]=fx; dep[x]=dep[fx]+1; siz[x]=1;
		for(R int i=head[x];i;i=e[i].next) {
			int y=e[i].to; if(y==fx) continue;
			dis[y]=dis[x]+e[i].w; dfs1(y,x); siz[x]+=siz[y];
			if(siz[y]>siz[son[x]]) son[x]=y;
		}
	}
	inline void dfs2(int x,int topx) {
		top[x]=topx;
		if(son[x]) dfs2(son[x],topx);
		for(R int i=head[x];i;i=e[i].next) {
			int y=e[i].to; 
			if(y==fa[x]||y==son[x]) continue;
			dfs2(y,y);
		}
	}
	inline int Lca(int x,int y) {
		while(top[x]!=top[y]) 
			if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];
			else y=fa[top[y]];
		return dep[x]<dep[y]?x:y;
	}
	inline int Dist(int x,int y) {
		return dis[x]+dis[y]-dis[Lca(x,y)]*2;
	}
	inline void Build() {
		dfs1(1,0); dfs2(1,1);
	}
}
namespace Tree {
	int Cnt,Head[MAXN];
	struct Edge { int to,rt,next; } E[MAXN<<1];
	inline void Add(int x,int y,int rt) {
		E[++Cnt]={ y, rt, Head[x] }; Head[x]=Cnt; 
	}
	int RT,Root,mx[MAXN],vis[MAXN],siz[MAXN],total,fa[MAXN];
	inline void findrt(int x,int fx) {
		mx[x]=0; siz[x]=1;
		for(R int i=Graph::head[x];i;i=Graph::e[i].next) {
			int y=Graph::e[i].to;
			if(y==fx||vis[y]) continue;
			findrt(y,x); siz[x]+=siz[y];
			mx[x]=max(mx[x],siz[y]);
		}
		mx[x]=max(mx[x],total-siz[x]);
		if(mx[x]<mx[Root]) Root=x;
	}
	inline void build(int x,int fx) {
		fa[x]=fx; vis[x]=1;
		for(R int i=Graph::head[x];i;i=Graph::e[i].next) {
			int y=Graph::e[i].to; if(vis[y]) continue;
			total=siz[y]; Root=0;
			findrt(y,0); Add(x,y,Root); 
			build(Root,x);
		}
	}
	inline void Build() {
		mx[0]=0x7f7f7f7f;
		Root=0; findrt(1,0);findrt(Root,0); RT=Root; build(Root,0);
	}
	LL sums[MAXN],su***XN],sumf[MAXN];
	inline void Modify(int x,int k) {
		sums[x]+=k;
		for(R int i=x;fa[i];i=fa[i]) {
			int len=Graph::Dist(x,fa[i]);
			sums[fa[i]]+=k;
			sumd[fa[i]]+=1LL*k*len;
			sumf[i]+=1LL*k*len;
		}
	}
	inline LL Count(int x) {
		LL res=sumd[x];
		for(R int i=x;fa[i];i=fa[i]) {
			int len=Graph::Dist(x,fa[i]);
			res+=(sums[fa[i]]-sums[i])*len;
			res+=sumd[fa[i]]-sumf[i];
		}
		return res;
	}
	inline LL Ask(int x) {
		LL res=Count(x);
		for(R int i=Head[x];i;i=E[i].next) {
			int y=E[i].to;
			if(Count(y)<res) return Ask(E[i].rt);
		}
		return res;
	}
	inline LL Ask() { return Ask(RT); }
}
int main() {
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	n=read(); q=read();
	for(R int i=1;i<n;i++) {
		int x=read(),y=read(),z=read();
		Graph::add(x,y,z); Graph::add(y,x,z);
	}
	Graph::Build(); Tree::Build();
	while(q--) {
		int x=read(),y=read();
		Tree::Modify(x,y);
		printf("%lld\n",Tree::Ask());
	}
	return 0;
}