运输计划
Posted mysblogs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运输计划相关的知识,希望对你有一定的参考价值。
传送门
解法:
首先要学会求 树的最近公共祖先(LCA)
没用树剖
用了一个经常可以代替树剖的方法
树上差分 这个方法很优秀 一定要掌握
首先 有了lca 就可以求树上两点间长度
设 \(d[x]\) 为 \(x\) 到 根节点 的距离
则 \(u\),\(v\) 间距离为 \(d[u]+d[v]-2*d[lca(u,v)]\)
同时可以实现差分
设 \(ver[x]\) 为 \(x\) 的差分数组
对于 \(u\),\(v\) 连边 覆盖原图边的差分处理 \(ver[u]++,ver[v]++,ver[lca(u,v)]-=2\)
在进行一次dfs就求到 每个点x到父节点的边 被覆盖的次数ver[x]
二分答案
对于每个\(u\),\(v\)若距离>二分的值
说明此时要在其覆盖的边中减去一条满足条件的
差分处理
设此时有cnt个路径要删边
那么能达到此时二分答案则必须有一条边被所有路径覆盖
即dfs后 存在\(ver[x]==cnt\)且此时删去改边后 最长的一条路径也要不大于此时答案
此答案才可行
最后二分求出的最大可行值即为答案
代码:
第一种 倍增法求lca O(nlogn+mlogm+(n+m)logSum) 可能会被卡掉一两个点 开O2能过
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 2000000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
int n,m,sum=0,ans;
int root=1,dep[300010],f[300010][20],lg2[300010],d[300010],ver[300010];
int tot=1,head[300010];
struct node
int u,v,lca,dis;
qu[300010];
struct EDGE
int to,nxt,d;
edge[600010];
queue<int> que;
inline void add(int u,int v,int d)
edge[++tot].to=v;
edge[tot].nxt=head[u];
edge[tot].d=d;
head[u]=tot;
inline void bfs()
dep[root]=1;
que.push(root);
while(!que.empty())
int x=que.front();que.pop();
for(int i=head[x];i;i=edge[i].nxt)
int y=edge[i].to;
if(dep[y]) continue;
f[y][0]=x;dep[y]=dep[x]+1;d[y]=d[x]+edge[i].d;
rep(j,1,lg2[dep[y]])
f[y][j]=f[f[y][j-1]][j-1];
que.push(y);
inline int lca(int x,int y)
if(dep[x]>dep[y]) swap(x,y);
dwn(i,lg2[dep[y]-dep[x]],0)
if(dep[f[y][i]]>=dep[x]) y=f[y][i];
if(x==y) return x;
dwn(i,lg2[dep[x]],0)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
void dfs(int x)
for(int i=head[x];i;i=edge[i].nxt)
int y=edge[i].to;
if(dep[x]>dep[y]) continue;
dfs(y);
ver[x]+=ver[y];
bool check(int mid)
memset(ver,0,sizeof(ver));
int cnt=0,maxn=0;
rep(i,1,m)
if(qu[i].dis>mid)
cnt++;
ver[qu[i].u]++,ver[qu[i].v]++,ver[qu[i].lca]-=2;
maxn=max(maxn,qu[i].dis-mid);
if(cnt==0) return 1;
dfs(root);
rep(i,1,n)
if(i!=root&&ver[i]==cnt&&d[i]-d[f[i][0]]>=maxn) return 1;
return 0;
int main()
scanf("%d%d",&n,&m);
rep(i,2,n)
lg2[i]=lg2[i>>1]+1;
rep(i,1,n-1)
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
add(u,v,d),add(v,u,d);
sum+=d;
bfs();
rep(i,1,m)
int u,v;
scanf("%d%d",&u,&v);
qu[i].lca=lca(u,v);
qu[i].dis=d[u]+d[v]-2*d[qu[i].lca];
qu[i].u=u,qu[i].v=v;
int l=0,r=sum;
while(l<=r)
int mid=(l+r)>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
printf("%d\n",ans);
return 0;
第二种 tarjan的lca算法 O(n+m+(n+m)logSum) 相对快一些 不用O2过
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 2000000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
int n,m,sum=0,ans;
int root=1,d[300010],fa[300010],ver[300010];
int tot=1,head[300010];
int v[300010],par[300010];
struct node
int u,v,lca,dis;
qu[300010];
struct EDGE
int to,nxt,d;
edge[600010];
queue<int> que;
vector<P> ques[300010];
inline void add(int u,int v,int d)
edge[++tot].to=v;
edge[tot].nxt=head[u];
edge[tot].d=d;
head[u]=tot;
inline void bfs()
que.push(root);
fa[root]=root;
while(!que.empty())
int x=que.front();que.pop();
for(int i=head[x];i;i=edge[i].nxt)
int y=edge[i].to;
if(fa[y]) continue;
d[y]=d[x]+edge[i].d;
fa[y]=x;
que.push(y);
int get(int x)
if(x==par[x]) return x;
return par[x]=get(par[x]);
void tarjan(int x)
v[x]=1;
for(int i=head[x];i;i=edge[i].nxt)
int y=edge[i].to;
if(v[y]) continue;
tarjan(y);
par[y]=x;
for(int i=0;i<ques[x].size();++i)
if(v[ques[x][i].first]==2)
qu[ques[x][i].second].lca=get(ques[x][i].first);
v[x]=2;
void dfs(int x)
for(int i=head[x];i;i=edge[i].nxt)
int y=edge[i].to;
if(fa[y]!=x) continue;
dfs(y);
ver[x]+=ver[y];
bool check(int mid)
memset(ver,0,sizeof(ver));
int cnt=0,maxn=0;
rep(i,1,m)
if(qu[i].dis>mid)
cnt++;
ver[qu[i].u]++,ver[qu[i].v]++,ver[qu[i].lca]-=2;
maxn=max(maxn,qu[i].dis-mid);
if(cnt==0) return 1;
dfs(root);
rep(i,1,n)
if(i!=root&&ver[i]==cnt&&d[i]-d[fa[i]]>=maxn) return 1;
return 0;
int main()
scanf("%d%d",&n,&m);
rep(i,1,n-1)
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
add(u,v,d),add(v,u,d);
sum+=d;
bfs();
rep(i,0,n) par[i]=i;
rep(i,1,m)
int u,v;
scanf("%d%d",&u,&v);
qu[i].u=u,qu[i].v=v;
if(u==v) qu[i].lca=u,qu[i].dis=0;
else ques[u].push_back(P(v,i)),ques[v].push_back(P(u,i));
tarjan(root);
rep(i,1,m) qu[i].dis=d[qu[i].u]+d[qu[i].v]-2*d[qu[i].lca];
int l=0,r=sum;
while(l<=r)
int mid=(l+r)>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
printf("%d\n",ans);
return 0;
以上是关于运输计划的主要内容,如果未能解决你的问题,请参考以下文章