1 条题解
-
0
自动搬运
来自洛谷,原作者为

是青白呀
咕咕咕?咕咕咕!搬运于
2025-08-24 23:05:36,当前版本为作者最后更新于2025-01-08 20:59:24,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
考虑一个建图方式:建立 个点表示病毒的中转点,对每个人的点 ,找到所有距离 小于等于 的树上点,它们的中转点向 连 的边, 向它们的中转点连 的边。直接跑 dij 可以做到 。
考虑优化“ 这个人向所有距离它小于等于 的中转点连权值为 的正向或反向边”。考虑点分治优化,一个深度为 的点能向所有深度小于等于 的点连边。下面以正向为例:考虑建立 个虚点,每个虚点向该深度下的实际中转点连 的边;虚点之间由深度 连 边;考察每个人对应的点,向 对应的虚点连 边。反向边只需要将上述所有边反向,且去掉虚点连出来的边的权值即可。
这样,点分治过程中每个连通块的点、边数为 ,总数为 级别。直接跑 dij 可以做到 ,已经可以通过了。
还有一些优化。对于每个中转点,我们再拆成入点和出点,这样只有 条出入点之间的边有权值。在 dij 的过程中,我们借用 01BFS 的思想,对于有权值的边,我们扔进优先队列;对于 权边,我们使用普通队列,直接维护。每次弹出时,优先弹出普通堆的点即可。这样只有 条边会进堆,复杂度做到 。似乎优化效果不明显。
#include<bits/stdc++.h> #define rep(i,j,k) for(int i=j;i<=k;i++) #define repp(i,j,k) for(int i=j;i>=k;i--) #define pii pair<int,int> #define mp make_pair #define fir first #define sec second #define ls(x) (x<<1) #define rs(x) ((x<<1)|1) #define lowbit(i) (i&-i) #define qingbai qwq using namespace std; typedef long long ll; const int N=1e5+5,M=2e6+5,mo=1e9+7; const ll inf=(ll)1e18+7; void read(int &a){ int x=0,w=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')w=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } a=x*w; } int n,m,p[N],d[N],c[N]; vector<int>et[N]; int cntp,id[N]; vector<int>perc[N]; int maxs[N],sz[N],rt,tot; bool vis[N]; void dfs1(int x,int f){ maxs[x]=0,sz[x]=1; for(auto j:et[x]){ if(vis[j]||j==f)continue; dfs1(j,x),sz[x]+=sz[j],maxs[x]=max(maxs[x],sz[j]); } maxs[x]=max(maxs[x],tot-sz[x]); if(maxs[x]<maxs[rt])rt=x; } vector<pii>e[N*45]; int dep[N],idd[N],maxd=0; void dfs2(int x,int f){ dep[x]=dep[f]+1,maxd=max(maxd,dep[x]); for(auto j:et[x]){ if(j==f||vis[j])continue; dfs2(j,x); } } void dfs3(int x,int f){ for(auto j:et[x]) if(j!=f&&!vis[j])dfs3(j,x); for(auto j:perc[x]){ int topos=min(maxd,d[j]-dep[x]); if(topos<0)continue; e[id[j]].push_back(mp(idd[topos],0)); e[idd[topos]+1].push_back(mp(id[j],0)); } e[idd[dep[x]]].push_back(mp(x,0)); e[x+n].push_back(mp(idd[dep[x]]+1,0)); } void dfz(int x){ maxd=0,dep[0]=-1,dfs2(x,0); rep(i,0,maxd) idd[i]=++cntp,cntp++; rep(i,1,maxd){ e[idd[i]].push_back(mp(idd[i-1],0)); e[idd[i-1]+1].push_back(mp(idd[i]+1,0)); } dfs3(x,0); vis[x]=1; for(auto j:et[x]){ if(vis[j])continue; rt=0,tot=sz[j],dfs1(j,x),dfz(rt); } } ll dis[N*45]; bool visd[N*45]; void dij(){ queue<pair<ll,int>>q; priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>pq; rep(i,1,cntp) dis[i]=inf,visd[i]=0; dis[id[1]]=0,pq.push(mp(0ll,id[1])); while(!q.empty()||!pq.empty()){ int x;ll v; if(!q.empty())tie(v,x)=q.front(),q.pop(); else tie(v,x)=pq.top(),pq.pop(); if(visd[x])continue; visd[x]=1; for(auto j:e[x]){ if(visd[j.fir]||dis[j.fir]<=dis[x]+j.sec)continue; dis[j.fir]=dis[x]+j.sec; if(!j.sec)q.push(mp(dis[j.fir],j.fir)); else pq.push(mp(dis[j.fir],j.fir)); } } } vector<ll>ans; vector<long long> find_spread(int N, int M, vector<int> A, vector<int> B, vector<int> P, vector<int> D, vector<int> C){ n=N,m=M,cntp=2*n; rep(i,0,n-2) et[A[i]+1].push_back(B[i]+1),et[B[i]+1].push_back(A[i]+1); rep(i,1,m) p[i]=P[i-1]+1,d[i]=D[i-1],perc[p[i]].push_back(i); rep(i,1,n) c[i]=C[i-1]; rep(i,1,m) id[i]=++cntp; tot=n,rt=0,maxs[0]=n+2,dfs1(1,0),dfz(rt); rep(i,1,n) e[i].push_back(mp(i+n,c[i])); dij(); rep(i,1,m){ if(dis[id[i]]==inf)ans.push_back(-1); else ans.push_back(dis[id[i]]); } return ans; }
- 1
信息
- ID
- 10944
- 时间
- 4000ms
- 内存
- 1000MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者