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

Scarlet
**搬运于
2025-08-24 21:28:11,当前版本为作者最后更新于2016-10-30 09:04:07,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
##转化问题
这里路线涨价明显等同于删边,所以我们可以把问题倒过来思考:
图上依次(倒序)加边,问每个点成为最终图最短路的时间 ##分析
记*原图*的点1到达点i的最短路为dis[i],*当前状态*下点1到达点i最短路为d[i]。下面称d[i]==dis[i]的点i为扩展点。
通过分析最短路性质发现,某个点v新成为扩展点情况有两个
-
加边(u,v)更新,且dis[u]==d[u]&&dis[v]==d[u]+1&&d[v]!=dis[v]。
-
邻居u突然成为最终图最短路,且dis[v]==d[u]+1&&d[v]!=dis[v]
_(其实上面是同一种情况XD)_
重要的是,每个点只会被更新1次,体现在了上面的强调处。这是很显然的,因为这题答案是唯一确定的,但这个是降低复杂度的重要条件。
##确定算法
-
首先把最终图的最短路情况dis[i]求出来。然后重建图,去掉所有待加边。
-
然后依次加入待加边,检测边的两端是否符合条件1,若符合,则进行深度优先搜索,对新成为扩展点邻居进行条件2判断。
-
将每次新成为扩展点的数目记录,最后处理出答案。
##复杂度分析
-
由于边权为1,求dis[]可以用bfs遍历,复杂度为O(n+m)。
-
加入了q条边,在整个过程2中每个点只会被dfs到一次,所以复杂度为O(n+m+q)。
-
每一次的答案是新成为扩展点的数目,所以需要一遍前缀和,复杂度为O(q)。
最终复杂度为O(n+m+q)
##代码
#include<bits/stdc++.h> #define maxn 400010 using namespace std; #define G c=getchar() inline int read() { int x=0,f=1;char G; while(c>57||c<48){if(c=='-')f=-1;G;} while(c>47&&c<58)x=x*10+c-48,G; return x*f; } #define AE(u,v) to[Si]=v,nxt[Si]=idx[u],idx[u]=Si++ int to[maxn],nxt[maxn],idx[maxn],Si; int n,m,q,dis[maxn],d[maxn]; queue<int>Q; int vis[maxn],b[maxn]; int E[maxn][2],qq[maxn],ans[maxn],tmp; void dfs(int u,int fa) { for(int i=idx[u];i+1;i=nxt[i]) if(to[i]!=fa&&dis[to[i]]==d[u]+1&&dis[to[i]]!=d[to[i]]) { d[to[i]]=d[u]+1;tmp++; dfs(to[i],u); } } void bfs(int s,int dis[]) { while(!Q.empty())Q.pop(); Q.push(s);dis[s]=0;vis[s]=1; while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=idx[u],v;i+1;i=nxt[i]) { if(vis[v=to[i]])continue; dis[v]=dis[u]+1; Q.push(v);vis[v]=1; } } } int main() { memset(idx,-1,sizeof(idx)); n=read(),m=read(),q=read(); for(int i=1;i<=m;i++) E[i][0]=read(),E[i][1]=read(),AE(E[i][0],E[i][1]),AE(E[i][1],E[i][0]); bfs(1,dis); memset(idx,-1,sizeof(idx));Si=0; memset(vis,0,sizeof(vis)); for(int i=1;i<=q;i++)qq[i]=read(),b[qq[i]]=1; for(int i=1;i<=m;i++) if(!b[i])AE(E[i][0],E[i][1]),AE(E[i][1],E[i][0]); bfs(1,d); for(int i=q;i>=1;i--) { int x=qq[i],u=E[x][0],v=E[x][1];tmp=0; if(dis[u]==d[u]&&dis[v]==d[u]+1&&d[v]!=dis[v])tmp++,d[v]=dis[v],dfs(v,u); swap(u,v); if(dis[u]==d[u]&&dis[v]==d[u]+1&&d[v]!=dis[v])tmp++,d[v]=dis[v],dfs(v,u); AE(u,v),AE(v,u); ans[i]=tmp; } for(int i=1;i<=q;i++) ans[i]+=ans[i-1],printf("%d\n",ans[i]); } -
- 1
信息
- ID
- 689
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者