专栏文章
题解:P1084 [NOIP 2012 提高组] 疫情控制
P1084题解参与者 5已保存评论 5
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @mipdgvxw
- 此快照首次捕获于
- 2025/12/03 10:12 3 个月前
- 此快照最后确认于
- 2025/12/03 10:12 3 个月前
有些坑点的题。
答案的单调性显然,考虑二分答案,首先能够发现向父亲走一定不劣,因为覆盖的节点更多了,那么我们已知最大时间为 ,令每一个点向上走尽量接近 的距离就好了,可是由于不能走到根,那么有的点可能还有剩余步数,但是只能暂时停在根的儿子下。
这样我们就能够得到一棵新树,如果一个被染色点不在根的儿子,那么其一定无法再移动了,所以我们之后的操作只需要对于根的儿子讨论即可。
对于新树,根有的子树内是覆盖不完整的,称为空子树,那么我们需要拿有多余点的子树去填空子树,一个很 naive 的想法是开两个小根堆,分别存空的和多余的到根的距离,匹配一下就做完了,这样确实挺对的,但只有 分。
考虑上述做法错在哪里,假设此时有根有三个儿子,,其中 为空, 均有一个染色点,其中距离 ,我们需要填满 ,那么刚才的做法可能是直接让 去 ,花费时间为 ,而另一种做法是先让 去 ,再让 去 ,时间为 ,在某些情况下是更优的。
讨论区一组直观的数据:
CPP4
1 2 99
1 3 1
1 4 99
3
3 4 4
答案为 。
因此,我们考虑优先将所有距离够的染色点提到根,对于来自于每一棵子树的点按照剩余步数排序,那么剩余步数多的肯定更加可能走到更远的未染色点,那么我们就要将距离短的放回本子树中保证子树被染色,放一个就好了,具体实现可以参考代码。
复杂度 ,因某些不可名状因素,采用树剖实现。
分实现:
CPPconst ll N=1e6+5,M=2e4+5;
ll n,m,fa[N],siz[N],id[N],w[N],son[N],dep[N],top[N],cnt,dis[N],Siz[N],vis[N];
vector<pii> g[N],E;vector<ll> P;
inline void dfs1(ll x,ll fat,ll depth){dep[x]=depth,siz[x]=1,fa[x]=fat;for(auto [y,w]:g[x]){if(y==fat) continue;dis[y]=dis[x]+w;dfs1(y,x,depth+1);siz[x]+=siz[y];if(siz[y]>siz[son[x]]) son[x]=y;}}
inline void dfs2(ll x,ll nowtop){top[x]=nowtop,id[x]=++cnt,w[cnt]=x;if(!son[x])return;dfs2(son[x],nowtop);for(auto [y,w]:g[x])if(y!=fa[x]&&y!=son[x]) dfs2(y,y);}
inline ll LCA(ll x,ll y){while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];return dep[x]<dep[y]?x:y;}
inline ll DIS(ll x,ll y){return dis[x]+dis[y]-2*dis[LCA(x,y)];}
inline ll LCApre(ll x,ll y){ll lst=x;while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?lst=top[y],y=fa[top[y]]:lst=top[x],x=fa[top[x]];if(dep[x]<dep[y]) swap(x,y);return x==y?lst:w[id[y]+1];}
inline ll ask_chain(ll x,ll pre,ll mid)
{
ll xx=x,y=pre;
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ll Top=max(id[pre],id[top[x]]);Top=w[Top];
if(dis[xx]-dis[Top]<mid){x=fa[top[x]];continue;}
ll l=id[Top],r=id[x];
while(l<r)
{
ll mid=l+r+1>>1;
if(dis[xx]-dis[w[mid]]<mid) r=mid-1;
else l=mid;
}
return w[l];
}
if(dep[x]<dep[y]) swap(x,y);
ll l=id[y],r=id[x];
while(l<r)
{
ll mid=l+r+1>>1;
if(dis[xx]-dis[w[mid]]<mid) r=mid-1;
else l=mid;
}
return w[l];
}
inline ll dfs3(ll x)
{
ll sum=0;for(auto [y,w]:g[x]) if(y!=fa[x]) sum+=dfs3(y);
return (g[x].size()!=1&&sum==g[x].size()-1)||(Siz[x]>0);
}
inline ll dfs4(ll x)
{
ll sum=0;for(auto [y,w]:g[x]) if(y!=fa[x]) sum+=dfs3(y);
return (g[x].size()!=1&&sum==g[x].size()-1);
}
inline bool check(ll mid)
{
priority_queue<pii,vector<pii>,greater<pii> > pq;
fo(0,i,n+1) Siz[i]=0,vis[i]=0;
for(ll i:P)
{
ll pre=LCApre(i,1);
if(dis[i]-dis[pre]<=mid) Siz[pre]++;
else Siz[ask_chain(i,pre,mid)]++;
if(dis[i]-dis[1]<=mid) pq.push(mp(mid-dis[i]+dis[1],pre));
}
for(auto [y,w]:g[1]) if(Siz[y]) vis[y]=dfs4(y);E.clear();
for(auto [y,w]:g[1]) if(!dfs3(y)) E.pb(mp(dis[y],y));sort(all(E));
ll ans=0;
for(auto [w,i]:E)
{
while(pq.size()&&(pq.top().fi<w||(!vis[pq.top().se]&&Siz[pq.top().se]<=1))) pq.pop();
if(pq.size())
{
Siz[pq.top().se]--,pq.pop(),ans++;
}
}
return ans==E.size();
}
signed main(){
read(n);ll u,v,w;
fo(1,i,n-1) read(u,v,w),g[u].pb(mp(v,w)),g[v].pb(mp(u,w));
dfs1(1,0,1),dfs2(1,1);
ll maxn=0,maxx=0;fo(1,i,n) if(dis[i]>=maxn) maxx=maxn,maxn=max(maxn,dis[i]);else if(dis[i]>=maxx) maxx=dis[i];
read(m);fo(1,i,m) read(u),P.pb(u);
ll l=0,r=1e14;
while(l<r)
{
ll mid=l+r>>1;
ll opt=check(mid);
if(opt) r=mid;
else l=mid+1;
}
wr(l==1e14?-1:l),pr;
return 0;
}
满分,区别只有
CPPcheck 函数:const ll N=1e6+5,M=2e4+5;
ll n,m,fa[N],siz[N],id[N],w[N],son[N],dep[N],top[N],cnt,dis[N],Siz[N],vis[N];
vector<pii> g[N],E;vector<ll> P;
inline void dfs1(ll x,ll fat,ll depth){dep[x]=depth,siz[x]=1,fa[x]=fat;for(auto [y,w]:g[x]){if(y==fat) continue;dis[y]=dis[x]+w;dfs1(y,x,depth+1);siz[x]+=siz[y];if(siz[y]>siz[son[x]]) son[x]=y;}}
inline void dfs2(ll x,ll nowtop){top[x]=nowtop,id[x]=++cnt,w[cnt]=x;if(!son[x])return;dfs2(son[x],nowtop);for(auto [y,w]:g[x])if(y!=fa[x]&&y!=son[x]) dfs2(y,y);}
inline ll LCA(ll x,ll y){while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];return dep[x]<dep[y]?x:y;}
inline ll LCApre(ll x,ll y){ll lst=x;while(top[x]^top[y]) dep[top[x]]<dep[top[y]]?lst=top[y],y=fa[top[y]]:lst=top[x],x=fa[top[x]];if(dep[x]<dep[y]) swap(x,y);return x==y?lst:w[id[y]+1];}
inline ll ask_chain(ll x,ll pre,ll mid)
{
ll xx=x,y=pre;
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ll Top=max(id[pre],id[top[x]]);Top=w[Top];
if(dis[xx]-dis[Top]<mid){x=fa[top[x]];continue;}
ll l=id[Top],r=id[x];
while(l<r)
{
ll mid=l+r+1>>1;
if(dis[xx]-dis[w[mid]]<mid) r=mid-1;
else l=mid;
}
return w[l];
}
if(dep[x]<dep[y]) swap(x,y);
ll l=id[y],r=id[x];
while(l<r)
{
ll mid=l+r+1>>1;
if(dis[xx]-dis[w[mid]]<mid) r=mid-1;
else l=mid;
}
return w[l];
}
inline ll dfs3(ll x)
{
ll sum=0;for(auto [y,w]:g[x]) if(y!=fa[x]) sum+=dfs3(y);
return (g[x].size()!=1&&sum==g[x].size()-1)||(Siz[x]>0);
}
inline ll dfs4(ll x)
{
ll sum=0;for(auto [y,w]:g[x]) if(y!=fa[x]) sum+=dfs3(y);
return (g[x].size()!=1&&sum==g[x].size()-1);
}
inline bool check(ll mid)
{
priority_queue<pii,vector<pii>,greater<pii> > pq;
fo(0,i,n+1) Siz[i]=0,vis[i]=0;ll ans=0;
vector<pii> E1,E2;
for(ll i:P)
{
ll pre=LCApre(i,1);
if(dis[i]-dis[pre]<=mid) E1.eb(mp(mid-dis[i]+dis[1],pre));
else Siz[ask_chain(i,pre,mid)]=1;
}
for(auto [y,w]:g[1]) Siz[y]=dfs4(y);
sort(all(E1));for(auto [w,i]:E1)if(w>0&&(Siz[i]||w>=dis[i])) pq.push(mp(w,i));else Siz[i]=1;
E.clear();for(auto [y,w]:g[1]) if(!dfs3(y)) E.pb(mp(dis[y],y));sort(all(E));
for(auto [w,i]:E)
{
while(pq.size()&&(pq.top().fi<w)) pq.pop();
if(pq.size()) Siz[pq.top().se]--,pq.pop(),ans++;
}
return ans==E.size();
}
signed main(){
read(n);ll u,v,w;
fo(1,i,n-1) read(u,v,w),g[u].pb(mp(v,w)),g[v].pb(mp(u,w));
read(m);fo(1,i,m) read(u),P.pb(u);
dfs1(1,0,1),dfs2(1,1);
ll l=0,r=1e14;
while(l<r)
{
ll mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
wr(l==1e14?-1:l),pr;
return 0;
}
相关推荐
评论
共 5 条评论,欢迎与作者交流。
正在加载评论...