[NOIP2015]运输计划

树剖学的好啊。。。
先预处理出来每个询问的距离,然后二分答案,check的时候树上差分一下,求出来大于mid的询问的最长公共边,减去以后判一下行不行。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=300006;
struct Edge{int to,nxt,val;}e[N<<1];
int head[N],ecnt,n,m,fa[N],dep[N],son[N],siz[N],dis[N],dfn[N],top[N],tim,vis[N],rnk[N],cost[N];
struct Q{int x,y,len;}q[N];
void add(int &bg,int &ed,int &val){e[++ecnt].nxt=head[bg];e[ecnt].to=ed;e[ecnt].val=val;head[bg]=ecnt;}
void dfs1(int x) {
  siz[x]=1;
  for(int i=head[x];i;i=e[i].nxt) {
    int v=e[i].to;
    if(v==fa[x]) continue;
    cost[v]=e[i].val;
    fa[v]=x;dep[v]=dep[x]+1;dis[v]=dis[x]+e[i].val;
    dfs1(v);
    siz[x]+=siz[v];
    if(siz[son[x]]<siz[v] ) son[x]=v;
  }
}
void dfs2(int x,int qtop) {
  dfn[x]=++tim;top[x]=qtop;rnk[tim]=cost[x];
  if(son[x]) dfs2(son[x],qtop);
  for(int i=head[x];i;i=e[i].nxt) {
    int v=e[i].to;
    if(v==fa[x]||v==son[x]) continue;
    dfs2(v,v);
  }
}
int lca(int x,int y) {
    while(top[x]!=top[y]) {
      if(dep[top[x]]<dep[top[y]]) swap(x,y);
      x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
bool cmp(Q x,Q y) {return x.len>y.len;}
int f[N];
void cf(int x,int y) {
  while(top[x]!=top[y]) {if(dep[top[x]]<dep[top[y]])swap(x,y);f[dfn[top[x]]]++,f[dfn[x]+1]--,x=fa[top[x]];}
  if(x==y) return;
  if(dep[x]>dep[y])swap(x,y);
  f[dfn[x]+1]++,f[dfn[y]+1]--;
}
int check(int &tim) {
  int cnt=1;
  while(q[cnt].len>tim) cnt++;
  cnt--;
  if(vis[cnt]) return vis[cnt];
  memset(f,0,sizeof f);
  for(int i=1;i<=cnt;i++)
    cf(q[i].x,q[i].y);
    int ans=0,mx=0;
  for(int i=1;i<=n;i++) {
    ans+=f[i];
    if(ans==cnt) mx=max(mx,rnk[i]);
  }
  return vis[cnt]=mx;
}
int main() {
  scanf("%d%d",&n,&m);
  for(int i=1,a,b,c;i<n;i++) {
    scanf("%d%d%d",&a,&b,&c);
    add(a,b,c);add(b,a,c);
  }
  dfs1(1),dfs2(1,1);
  for(int i=1,a,b;i<=m;i++)
    scanf("%d%d",&q[i].x,&q[i].y),q[i].len=dis[q[i].x]+dis[q[i].y]-(dis[lca(q[i].x,q[i].y)]<<1);
  sort(q+1,q+1+m,cmp);
  int l=0,r=q[1].len;
  while(l<=r) {
    int mid=l+r>>1;
    if(q[1].len-check(mid)>mid) l=mid+1;
    else r=mid-1;
  }
  printf("%d",l);
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9363498.html