题解:[NOIP 2015 提高组] 运输计划
题意分析
令最短时间为 \(mid\)。
那么我们显然可以二分枚举 \(mid\),因为其具有单调性——\(mid\) 越大,则可供选择的虫洞方案就越多。
那么考虑如何较为高效地判断 \(mid\) 是否可行。
考虑到权值小于等于 \(mid\) 的计划不需要考虑,那么虫洞所在边一定是其余计划的公共边。
则可以用树上差分求出这些公共边是哪些,然后枚举删除即可。
判断删去之后能否成功,只需要判断权值最大的计划的权值减去该边的权值是否小于 \(mid\) 即可。
时间复杂度:\(\mathcal O\left(n\log n+(n+m)\log V\right)\),\(V\) 为答案值域大小。
卡常
求路径长度需要 lca,使用“DFS 序+ST 表”即可。
每次清空树上差分数组时,可使用时间戳优化。
快读。
记 \(w\) 为所有计划的最大权值,\(t\) 为最长边的权值,则答案是在 \([w-t,w]\) 中的。
因此答案值域 \(V=t\),\(V\) 有上界 \(1000\)。
卡常之后时间复杂度为 \(\mathcal O(n\log n)\)。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
#define getchar getchar_unlocked
#define putchar putchar_unlocked
constexpr const int N=3e5,M=3e5,T=1000;
vector<pair<int,int> >g[N+1];
int n,m;
struct Plan{
int u,v,w;
}plan[M+1];
int st[N+1][__lg(N)+1],rest[N+1][__lg(N)+1],father[N+1],depth[N+1],order[N+1],first[N+1],sum[N+1];
void dfs(int x,int fx){
static int cnt;
order[++cnt]=x;
first[x]=cnt;
father[x]=fx;
depth[x]=depth[fx]+1;
for(auto i:g[x]){
if(i.first==fx){
continue;
}
sum[i.first]=sum[x]+i.second;
dfs(i.first,x);
}
}
void lca_pre(){
dfs(1,0);
for(int i=1;i<=n;i++){
st[i][0]=depth[order[i]];
rest[i][0]=order[i];
}
for(int i=1;(1<<i)<=n;i++){
for(int x=1;x+(1<<i)-1<=n;x++){
int &plA=st[x][i-1],&plB=st[x+(1<<i-1)][i-1];
if(plA<plB){
st[x][i]=plA;
rest[x][i]=rest[x][i-1];
}else{
st[x][i]=plB;
rest[x][i]=rest[x+(1<<i-1)][i-1];
}
}
}
}
int lca(int u,int v){
if(u==v){
return u;
}
if(first[u]>first[v]){
swap(u,v);
}
int s=__lg(first[v]-first[u]);
if(st[first[u]+1][s]<st[first[v]-(1<<s)+1][s]){
return father[rest[first[u]+1][s]];
}else{
return father[rest[first[v]-(1<<s)+1][s]];
}
}
int diff[N+1],tag[N+1],Time;
void dfs2(int x,int fx){
if(tag[x]!=Time){
tag[x]=Time;
diff[x]=0;
}
for(auto i:g[x]){
if(i.first==fx){
continue;
}
dfs2(i.first,x);
diff[x]+=diff[i.first];
}
}
bool check(int mid){
Time++;
int all=0;
int Max=-1;
for(int i=1;i<=m;i++){
if(plan[i].w>mid){
int &u=plan[i].u,&v=plan[i].v;
int p=lca(u,v);
if(tag[p]!=Time){
tag[p]=Time;
diff[p]=0;
}
diff[p]-=2;
if(tag[u]!=Time){
tag[u]=Time;
diff[u]=0;
}
if(tag[v]!=Time){
tag[v]=Time;
diff[v]=0;
}
diff[u]++,diff[v]++;
all++;
Max=max(Max,plan[i].w);
}
}
dfs2(1,0);
for(int i=1;i<=n;i++){
if(diff[i]==all){
if(Max-(sum[i]-sum[father[i]])<=mid){
return true;
}
}
}
return false;
}
template<typename T>
inline void Read(T &x){
x=0;
register int f=1;
register char ch=getchar();
for(;ch<'0'||'9'<ch;ch=getchar())if(ch=='-')f=-1;
for(;'0'<=ch&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
x*=f;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
Read(n);Read(m);
// cin>>n>>m;
int maxT=0;
for(int i=1;i<n;i++){
int a,b,t;
Read(a);Read(b);Read(t);
// cin>>a>>b>>t;
g[a].push_back({b,t});
g[b].push_back({a,t});
maxT=max(maxT,t);
}
lca_pre();
for(int i=1;i<=m;i++){
int &u=plan[i].u,&v=plan[i].v;
Read(u);Read(v);
// cin>>u>>v;
int p=lca(u,v);
plan[i].w=sum[u]+sum[v]-(sum[p]<<1);
}
int maxW=0;
for(int i=1;i<=m;i++){
maxW=max(maxW,plan[i].w);
}
int l=maxW-maxT,r=maxW+1;
while(l<r){
int mid=l+r>>1;
if(check(mid)){
r=mid;
}else{
l=mid+1;
}
}
cout<<r<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号