首先答案一定是包含直徑某個端點的一個連通塊裡所有邊權值之和,設直徑為$AB$,以$A$和$B$分別為根進行處理。
首先按照最長路法則將這棵樹進行樹鏈剖分,那麼每個葉子的貢獻為它與它所在鏈頂端的點的距離。
將葉子按貢獻從大到小排序,並求出$h[x]$表示$x$子樹內葉子排名的最小值。
對於詢問$(x,k)$,需要取$2k-1$個葉子。
如果$h[x]\leq k$,那麼說明前$2k-1$個葉子形成的連通塊經過了$x$點,直接返回前$2k-1$個葉子的貢獻和即可。
否則對於一個選中的葉子$y$,如果它頂端不是$x$的祖先,那麼踢掉$y$的代價為$y$的貢獻。
否則踢掉$y$的代價為$y$到$lca(x,y)$的距離。
那麼對於最優情況,要麼踢掉第$2k-1$大的葉子,要麼踢掉第二種情況裡深度最大的葉子$y$。找到這個$y$可以通過輕重鏈剖分+二分查詢得到。
總時間複雜度為$O((n+m)\log n)$。
#include<cstdio> #include<algorithm> #define N 100010 using namespace std; int n,m,i,x,y,z,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed,d[N],val[N],A,B; inline bool cmp(int x,int y){return val[x]>val[y];} inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;} void dfs(int x,int y){ if(d[x]>=d[z])z=x; for(int i=g[x];i;i=nxt[i])if(v[i]!=y)d[v[i]]=d[x]+w[i],dfs(v[i],x); } struct DS{ int s[N],f[N],d[N],son[N],top[N],m,q[N],sum[N],h[N]; int size[N],SON[N],TOP[N],dfn,loc[N],seq[N]; void dfs(int x){ for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){ s[v[i]]=s[x]+w[i],f[v[i]]=x,dfs(v[i]); if(d[v[i]]+w[i]>=d[x])d[x]=d[son[x]=v[i]]+w[i]; } } void dfs2(int x,int y){ top[x]=y;val[x]=s[x]-s[y]; if(!son[x]){q[++m]=x;return;} dfs2(son[x],y); for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],x); } void dfs3(int x){ if(!h[x])h[x]=m; size[x]=1; for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){ dfs3(v[i]),h[x]=min(h[x],h[v[i]]),size[x]+=size[v[i]]; if(size[v[i]]>size[SON[x]])SON[x]=v[i]; } } void dfs4(int x,int y){ TOP[x]=y;seq[loc[x]=++dfn]=x; if(SON[x])dfs4(SON[x],y); for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=SON[x])dfs4(v[i],v[i]); } void init(int S){ dfs(S),dfs2(S,S); sort(q+1,q+m+1,cmp); for(int i=1;i<=m;i++)h[q[i]]=i,sum[i]=sum[i-1]+val[q[i]]; dfs3(S),dfs4(S,S); } inline int ask(int l,int r,int k){ int t,mid; while(l<=r)if(h[seq[mid=(l+r)>>1]]<=k)l=(t=mid)+1;else r=mid-1; return seq[t]; } inline int lca(int x,int k){for(;x;x=f[TOP[x]])if(h[TOP[x]]<=k)return ask(loc[TOP[x]],loc[x],k);} inline int query(int x,int k){ k=k*2-1; if(k>=m)return sum[m]; if(h[x]<=k)return sum[k]; int y=lca(x,k); return sum[k]+s[q[h[x]]]-s[y]-min(s[q[k]]-s[top[q[k]]],s[q[h[y]]]-s[y]); } }DA,DB; int main(){ read(n),read(m); for(i=1;i<n;i++)read(x),read(y),read(z),add(x,y,z),add(y,x,z); dfs(1,z=0);A=z; for(i=1;i<=n;i++)d[i]=0; dfs(A,z=0);B=z; DA.init(A),DB.init(B); while(m--)read(x),read(y),printf("%d\n",max(DA.query(x,y),DB.query(x,y))); return 0; }