BZOJ3607 : 数据网络
首先答案一定是包含直径某个端点的一个连通块里所有边权值之和,设直径为$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; }