看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验。`````
检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是、要让所有$>\text{mid}$的链长通过找出一个为0的公共边减掉而全部变为$\le\text{mid}$的。
那么,统计出这$tot$条超出$\text{mid}$的链的路径上覆盖的边,一条被覆盖了$tot$次的边就可能具备条件,于是贪心找最大的满足条件的边,看是否可以把所有链(也就是最长链)搞成$\le\text{mid}$的,$O(n)$树上差分即可。
于是$O(n\text{log}len)$。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define dbg(x) cerr << #x << " = " << x <<endl 7 using namespace std; 8 typedef long long ll; 9 typedef double db; 10 typedef pair<int,int> pii; 11 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 12 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 16 template<typename T>inline T read(T&x){ 17 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 18 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 19 } 20 const int N=3e5+7; 21 struct thxorz{int to,nxt,w;}G[N<<1]; 22 struct stothx{int to,nxt,id;}Q[N<<1]; 23 struct query{int x,y,lca,dis;}q[N]; 24 int Head[N],tot=1,qh[N],qt; 25 int n,m,L,R,maxdis,maxe; 26 inline void Addedge(int x,int y,int z){ 27 G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z; 28 G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot,G[tot].w=z; 29 } 30 inline void AddQuery(int x,int y,int id){ 31 Q[++qt].to=y,Q[qt].nxt=qh[x],qh[x]=qt,Q[qt].id=id; 32 Q[++qt].to=x,Q[qt].nxt=qh[y],qh[y]=qt,Q[qt].id=id; 33 } 34 #define y G[j].to 35 #define qy Q[j].to 36 int vis[N],anc[N],dep[N]; 37 int get_anc(int x){return x==anc[x]?x:anc[x]=get_anc(anc[x]);} 38 void tarjan(int x,int fa){ 39 anc[x]=x; 40 for(register int j=Head[x];j;j=G[j].nxt)if(y^fa)dep[y]=dep[x]+G[j].w,tarjan(y,x),anc[y]=x; 41 vis[x]=1; 42 for(register int j=qh[x];j;j=Q[j].nxt)if(vis[qy]) 43 q[Q[j].id].lca=get_anc(qy),q[Q[j].id].dis=dep[x]+dep[qy]-(dep[q[Q[j].id].lca]<<1),MAX(R,q[Q[j].id].dis); 44 } 45 int d[N],del,cnt; 46 int dfs(int x,int c){ 47 int ret=d[x]; 48 for(register int j=Head[x];j;j=G[j].nxt)if(y^G[c^1].to)ret+=dfs(y,j); 49 if(ret==cnt)MAX(del,G[c].w); 50 return ret; 51 } 52 #undef y 53 #undef qy 54 inline int check(int mid){ 55 memset(d,0,sizeof d),del=cnt=0; 56 for(register int i=1;i<=m;++i)if(q[i].dis>mid)++d[q[i].x],++d[q[i].y],d[q[i].lca]-=2,++cnt; 57 dfs(1,0); 58 return maxdis-del<=mid; 59 } 60 int main(){//freopen("test.in","r",stdin);freopen("test.ans","w",stdout); 61 read(n),read(m); 62 for(register int i=1,x,y,z;i<n;++i)read(x),read(y),read(z),Addedge(x,y,z),MAX(L,z); 63 for(register int i=1;i<=m;++i)read(q[i].x),read(q[i].y),AddQuery(q[i].x,q[i].y,i); 64 tarjan(1,0);maxdis=R,maxe=L;L=R-L;//dbg(maxdis),dbg(maxe); 65 while(L<R){ 66 int mid=L+R>>1; 67 if(check(mid))R=mid; 68 else L=mid+1; 69 } 70 printf("%d\n",L); 71 return 0; 72 }
总结反思:瓶颈在check。关键在于要放眼全部,不要都放在maxdis上;求边若干次覆盖的统计可以往树上差分上想。