P2680 [NOIP2015 提高组] 运输计划
考察:LCA+二分答案
这题也太难想了,本蒟蒻完全不会QAQ
思路:
树上建边,然后每个任务都是一个查询,我们可以利用LCA求出树上任意两点的时间和.这道题要求去除一条边后最小的最大值.
两个最字很容易想到二分答案.假设二分答案为mid.对于每一个任务,检测它的时间是否会>mid.如果会统计>的任务数cnt.我们要找到一条所有时间过大的任务的公共边.删除这条边后,能让所有任务<=mid.某条边在所有不合时间的任务里出现 == 某条边在所有不合时间的路径里出现 cnt次.快速求遍历边的次数可以想到树上差分.每次找到cnt次的最大边.在检查减去这条边后是否符合即可.
1 #include <iostream> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 typedef long long LL; 6 const int N = 300010,M = 20; 7 int h[N],idx,n,m,fa[N][M],depth[N],d[N],dist[N],res,cnt; 8 struct Road{ 9 int fr,to,ne,w; 10 }road[N<<1]; 11 struct Path{ 12 int u,v,anc; 13 LL w; 14 }path[N]; 15 void add(int a,int b,int w) 16 { 17 road[idx].w = w,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 18 } 19 void bfs(int s) 20 { 21 queue<int> q; 22 q.push(s); 23 memset(depth,0x3f,sizeof depth); 24 depth[s] = 1,depth[0] = 0; 25 while(q.size()) 26 { 27 int u = q.front(); 28 q.pop(); 29 for(int i=h[u];~i;i=road[i].ne) 30 { 31 int v = road[i].to; 32 if(depth[v]>depth[u]+1) 33 { 34 depth[v] = depth[u]+1; 35 dist[v] = dist[u]+road[i].w; 36 q.push(v); 37 fa[v][0] = u; 38 for(int j=1;j<=19;j++) 39 fa[v][j] = fa[fa[v][j-1]][j-1]; 40 } 41 } 42 } 43 } 44 int lca(int a,int b) 45 { 46 if(depth[a]<depth[b]) swap(a,b); 47 for(int i=19;i>=0;i--) 48 if(depth[fa[a][i]]>=depth[b]) a = fa[a][i]; 49 if(a==b) return a; 50 for(int i=19;i>=0;i--) 51 if(fa[a][i]!=fa[b][i]) a = fa[a][i],b = fa[b][i]; 52 return fa[a][0]; 53 } 54 void dfs(int u,int fa) 55 { 56 for(int i=h[u];~i;i=road[i].ne) 57 { 58 int v =road[i].to; 59 if(v==fa) continue; 60 dfs(v,u); 61 d[u]+=d[v]; 62 } 63 int dis = dist[u]; 64 if(fa!=-1) dis-=dist[fa]; 65 if(cnt<=d[u]&&dis>res) res = dis; 66 } 67 bool check(LL mid) 68 { 69 cnt = 0;res = 0; 70 memset(d,0,sizeof d); 71 for(int i=1;i<=m;i++) 72 if(path[i].w>mid) 73 { 74 cnt++;//求多少条不满足的路径 75 d[path[i].u]++,d[path[i].v]++,d[path[i].anc]-=2; 76 } 77 if(!cnt) return 1; 78 dfs(1,-1); 79 for(int i=1;i<=m;i++) 80 if(path[i].w-res>mid) return 0; 81 return 1; 82 } 83 int main() 84 { 85 scanf("%d%d",&n,&m); 86 memset(h,-1,sizeof h); 87 for(int i=1;i<n;i++) 88 { 89 int a,b,w; scanf("%d%d%d",&a,&b,&w); 90 add(a,b,w); add(b,a,w); 91 } 92 bfs(1); 93 LL l = 0,r = 0; 94 for(int i=1;i<=m;i++) 95 { 96 int a,b; scanf("%d%d",&a,&b); 97 int anc = lca(a,b); 98 LL w = dist[a]+dist[b]-2*dist[anc]; 99 path[i] = {a,b,anc,w}; 100 r= max(w,r); 101 } 102 while(l<r) 103 { 104 LL mid = l+r>>1; 105 if(check(mid)) r = mid; 106 else l = mid+1; 107 } 108 printf("%lld\n",r); 109 return 0; 110 }