[luogu2680]运输计划
首先二分枚举答案t,考虑删去的边应满足的条件——所有大于t的链全部经过且长度不小于最长链-t,第二个条件很好判断,考虑第一个条件。
先考虑有祖先-后代关系的链,用如果把这条链到1看成一个序列,那么差分一下再dfs一遍就可以对这条链上每一个点打上标记。
然后没有祖先-后代关系的链,同样可以分解成两条链,到x到lca(x,y)和y到lca(x,y),同样处理即可,最后时间复杂度o(nlogn)(lca预处理)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 struct ji{ 5 int nex,to,len; 6 }edge[N<<1]; 7 int E,n,m,x,y,z,a[N],b[N],c[N],head[N],f[N][21],in[N],out[N],s[N],dp[N],ans[N]; 8 void add(int x,int y,int z){ 9 edge[E].nex=head[x]; 10 edge[E].to=y; 11 edge[E].len=z; 12 head[x]=E++; 13 } 14 bool pd(int x,int y){ 15 return (in[x]<=in[y])&&(out[y]<=out[x]); 16 } 17 int lca(int x,int y){ 18 if (pd(x,y))return x; 19 for(int i=20;i>=0;i--) 20 if (!pd(f[x][i],y))x=f[x][i]; 21 return f[x][0]; 22 } 23 void dfs(int k,int fa,int sh){ 24 f[k][0]=fa; 25 for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1]; 26 s[k]=sh; 27 in[k]=++x; 28 for(int i=head[k];i!=-1;i=edge[i].nex) 29 if (edge[i].to!=fa)dfs(edge[i].to,k,sh+edge[i].len); 30 out[k]=++x; 31 } 32 void dfs2(int k,int fa){ 33 for(int i=head[k];i!=-1;i=edge[i].nex) 34 if (edge[i].to!=fa){ 35 dfs2(edge[i].to,k); 36 dp[k]+=dp[edge[i].to]; 37 } 38 } 39 bool pd(int k){ 40 int tot=0; 41 memset(dp,0,sizeof(dp)); 42 for(int i=1;i<=m;i++) 43 if (ans[i]>k){ 44 dp[a[i]]++; 45 dp[b[i]]++; 46 dp[c[i]]-=2; 47 tot++; 48 } 49 dfs2(1,0); 50 for(int i=1;i<=n;i++) 51 if ((dp[i]==tot)&&(s[i]-s[f[i][0]]>=ans[0]-k))return 1; 52 return 0; 53 } 54 int main(){ 55 scanf("%d%d",&n,&m); 56 memset(head,-1,sizeof(head)); 57 for(int i=1;i<n;i++){ 58 scanf("%d%d%d",&x,&y,&z); 59 add(x,y,z); 60 add(y,x,z); 61 } 62 dfs(1,1,x=0); 63 for(int i=1;i<=m;i++){ 64 scanf("%d%d",&a[i],&b[i]); 65 c[i]=lca(a[i],b[i]); 66 ans[i]=s[a[i]]+s[b[i]]-2*s[c[i]]; 67 ans[0]=max(ans[0],ans[i]); 68 } 69 x=0; 70 y=ans[0]; 71 while (x<y){ 72 z=(x+y>>1); 73 if (pd(z))y=z; 74 else x=z+1; 75 } 76 printf("%d",x); 77 }