loj2425 「NOIP2015」运输计划[二分答案+树上差分]

看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\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 }
View Code

总结反思:瓶颈在check。关键在于要放眼全部,不要都放在maxdis上;求边若干次覆盖的统计可以往树上差分上想。

猜你喜欢

转载自www.cnblogs.com/saigyouji-yuyuko/p/11587424.html