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;
}

  

posted @ 2016-02-29 23:09  Claris  阅读(564)  评论(0编辑  收藏  举报