[luogu2680]运输计划

首先二分枚举答案t,考虑删去的边应满足的条件——所有大于t的链全部经过且长度不小于最长链-t,第二个条件很好判断,考虑第一个条件。

先考虑有祖先-后代关系的链,用如果把这条链到1看成一个序列,那么差分一下再dfs一遍就可以对这条链上每一个点打上标记。

然后没有祖先-后代关系的链,同样可以分解成两条链,到xlca(x,y)ylca(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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11272087.html