题面
分析
好题。
概括一下题意:在可以将一条边权变为0的情况下,求完成m条路线的最长时间的最小值。
概括出来后可以明显发现是二分的标配,单调性显然,如果mid的时间是答案,比mid小的任务肯定能完成,如果有任务完不成,说明时间比mid大。
而这m条路线又是树上边差分的暗示。
所以很明显我们需要二分+树上差分。
可以先在 MlogN 的时间复杂度内预处理出每条航线的路径长度,只需通过预处理每个点到根的距离再求lca即可。
直接二分时间。将mid时间内的航线忽略,将时间比mid大的航线打上标记(把边塞给点式标记)
最后我们只需要判断一下,所有时间比mid大的航线公共的边中,最大的那一条长度是多少。如果最长的航线减去这个长度能达成小于mid即为成立。
虽然此题卡常,但是稍微常数优化一下,少个排序,加个读优,上register之类的,也没多大问题,至少水谷过了。。
代码
- #include<bits/stdc++.h>
- using namespace std;
- #define N 300030
- #define RT register
- int n,m,l,r,cnt,num,now,mid,maxx;
- int c[N],d[N],wv[N],dep[N],first[N],fa[N][20];
- struct email
- {
- int u,v,w;
- int nxt;
- }e[N*4];
- struct query
- {
- int x,y,dis;
- }q[N];
- template<class T>
- inline void read(T &x)
- {
- x=0;int f=1;static char c=getchar();
- while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
- while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
- x*=f;
- }
- inline void add(int u,int v,int w)
- {
- e[++cnt].nxt=first[u];first[u]=cnt;
- e[cnt].u=u;e[cnt].v=v;e[cnt].w=w;
- }
- inline void pre(int u,int f,int w)
- {
- wv[u]=w;//把边塞给点
- for(RT int i=1;(1<<i)<=dep[u];++i)
- fa[u][i]=fa[fa[u][i-1]][i-1];
- for(RT int i=first[u];i;i=e[i].nxt)
- {
- int v=e[i].v,w=e[i].w;
- if(v==f)continue;
- dep[v]=dep[u]+1;
- d[v]=d[u]+w;fa[v][0]=u;
- pre(v,u,w);
- }
- }
- inline int lca(int x,int y)
- {
- if(dep[x]<dep[y])swap(x,y);
- int t=dep[x]-dep[y];
- for(RT int i=0;(1<<i)<=t;++i)
- if((1<<i)&t)
- x=fa[x][i];
- if(x==y)return x;
- for(RT int i=19;i>=0;--i)
- if(fa[x][i]!=fa[y][i])
- x=fa[x][i],y=fa[y][i];
- return fa[x][0];
- }
- inline void dfs(int u,int f)
- {
- for(RT int i=first[u];i;i=e[i].nxt)
- {
- int v=e[i].v;
- if(v==f)continue;
- dfs(v,u);
- c[u]+=c[v];
- }
- }
- inline int check(int x)
- {
- now=num=0;memset(c,0,sizeof(c));
- for(RT int i=1;i<=m;++i)
- {
- if(q[i].dis<=x)continue;
- ++c[q[i].x],++c[q[i].y],c[lca(q[i].x,q[i].y)]-=2;
- ++num;
- }
- dfs(1,0);
- for(RT int i=1;i<=n;++i)
- if(num==c[i])now=max(now,wv[i]);
- return maxx-now<=x;
- }
- int main()
- {
- read(n);read(m);
- for(RT int i=1;i<n;++i)
- {
- int u,v,w;
- read(u),read(v);read(w);
- add(u,v,w);add(v,u,w);
- }
- pre(1,0,0);
- for(RT int i=1;i<=m;++i)
- {
- read(q[i].x),read(q[i].y);
- int LCA=lca(q[i].x,q[i].y);
- q[i].dis=d[q[i].x]+d[q[i].y]-2*d[LCA];
- r=max(r,q[i].dis);
- }
- maxx=r;
- while(l<r)
- {
- mid=l+r>>1;
- if(check(mid))r=mid;
- else l=mid+1;
- }
- printf("%d ",r);
- return 0;
- }