BZOJ3607 : 資料網路

Claris發表於2016-02-29

首先答案一定是包含直徑某個端點的一個連通塊裡所有邊權值之和,設直徑為$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;
}

  

相關文章