NOIP的神题......其难度与质量媲美之后一年的天天爱跑步......被奉为神题......
题意简述:给定一颗$N$个点边带权的树,再给定$M$条链,问将树上的某条边权值改为0后,这些链中最长的至少有多长。
由于答案显然具有单调性,因此可以考虑二分答案。
二分答案后就变成了这样一个问题:将一条边的边权变为0后,是否可以让所有m条路径中每条的权值都小于$mid$;
这个问题乍一看还是没啥思路,不妨更加深入的分情况来看。
对于权值和小于$mid$的链,怎么改他也是符合条件的,因此可以不考虑。
对于权值和大于$mid$的链,由于只能修改一条边,因此我们必须找到一条边使得其为所有链长大于$mid$的指定链的公共部分。
光是公共部分还不够,还需要有长度限制。设$m$条链中长度最长的为$mx$,则我们找到的边必须要大于等于$mx-mid$
对于第二个问题十分好解决,直接看这条边的边权即可。
对于第一个问题,我们使用树上差分的方式,将每条边被覆盖的次数进行统计,此外,我们可以提前处理出来所有链的$LCA$,这样可以省去许多时间
参考代码如下:
1 #pragma GCC optinize(3) 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #define N 600005 6 using namespace std; 7 int read() 8 { 9 int x=0,f=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 12 return x*f; 13 } 14 int n,m,v[N],w[N],head[N],nxt[N],cnt,fa[N][22],dep[N],maxn,_maxn,s[N],t[N],dist[N],lca[N],distt[N]; 15 int cf[N],scf[N]; 16 void dfs(int x,int f,int dis) 17 { 18 dep[x]=dep[f]+1; 19 distt[x]=dis; 20 for(int i=0;i<=19;i++)fa[x][i+1]=fa[fa[x][i]][i]; 21 for(int i=head[x];i;i=nxt[i]) 22 { 23 if(v[i]==f)continue; 24 fa[v[i]][0]=x; 25 dfs(v[i],x,dis+w[i]); 26 } 27 } 28 void dfs1(int x,int f) 29 { 30 scf[x]=cf[x]; 31 for(int i=head[x];i;i=nxt[i]) 32 { 33 if(v[i]==f)continue; 34 dfs1(v[i],x); 35 scf[x]+=scf[v[i]]; 36 } 37 } 38 bool dfs2(int x,int f,int c,int len) 39 { 40 for(int i=head[x];i;i=nxt[i]) 41 { 42 if(v[i]==f)continue; 43 if(scf[v[i]]==c&&w[i]>=len)return 1; 44 if(dfs2(v[i],x,c,len))return 1; 45 } 46 return 0; 47 } 48 int LCA(int x,int y) 49 { 50 if(dep[x]<dep[y])swap(x,y); 51 for(int i=20;i>=0;i--) 52 { 53 if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; 54 if(x==y)return x; 55 } 56 for(int i=20;i>=0;i--) 57 { 58 if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; 59 } 60 return fa[x][0]; 61 } 62 void add(int a,int b,int c) 63 { 64 v[++cnt]=b; 65 w[cnt]=c; 66 nxt[cnt]=head[a]; 67 head[a]=cnt; 68 } 69 bool check(int x) 70 { 71 if(x>=_maxn)return 1; 72 memset(cf,0,sizeof(cf)); 73 memset(scf,0,sizeof(scf)); 74 int _cnt=0; 75 for(int i=1;i<=m;i++) 76 { 77 if(dist[i]>x) 78 { 79 _cnt++; 80 cf[s[i]]++;cf[t[i]]++; 81 cf[lca[i]]-=2; 82 } 83 } 84 dfs1(1,0); 85 return dfs2(1,0,_cnt,_maxn-x); 86 } 87 int main() 88 { 89 n=read();m=read(); 90 for(int x,y,z,i=1;i<n;i++) 91 { 92 x=read();y=read();z=read(); 93 maxn=max(maxn,z); 94 add(x,y,z);add(y,x,z); 95 } 96 dfs(1,0,0); 97 for(int i=1;i<=m;i++) 98 { 99 s[i]=read();t[i]=read(); 100 lca[i]=LCA(s[i],t[i]); 101 dist[i]=distt[s[i]]+distt[t[i]]-2*distt[lca[i]]; 102 _maxn=max(_maxn,dist[i]); 103 } 104 int l=_maxn-maxn,r=_maxn+1,mid; 105 while(l<=r) 106 { 107 mid=(l+r)>>1; 108 if(check(mid))r=mid-1; 109 else l=mid+1; 110 } 111 printf("%d\n",l); 112 return 0; 113 }