洛谷 1710
Posted TSOI_Vergil
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 1710相关的知识,希望对你有一定的参考价值。
这道题是一道图论题,题目的意思是每次删除一条边,询问当前有多少点与1号节点的最短路的值与未删边之前不同。首先我们一定是求出原图的最短路,由于我们可以默认边权是1,于是我们可以BFS,这样我们就能够得到一张“最短路图”,所谓最短路图就是说对于一条边(u,v),我们只走dis[v]=dis[u]+1的边,这样如果删除的边不是最短路图上的边,对其他点是没有任何影响的,那我们考虑如果删除最短路图上的边,只要这条边的端点还在最短路图中能被1号点访问到,那么它的最短路一定不会变化,那我们怎么维护呢,感觉正着做很不好搞,因为删除一条边后,即使它的两端点不与1连通,它的两端点的点也可能与1连通,我们考虑正难则反,离线处理,将删边变成加边,维护一个bz数组表示每个点是否已经和1连通,这样,每加进一条边,我们判断它能否将1与边的出点连通,如果连通,我们就从这条边的出点DFS,将所有bz[i]=0的点变成1,对于每个bz[i]=1的点,我们不再进行DFS,这样就保证了每个点只被访问1次,也就保证了复杂度是线性的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 400005
int n,m,q,l=1,w=0;
int pre[maxn],other[maxn],last[maxn];
int pre1[maxn],other1[maxn],last1[maxn];
int dis[maxn],que[maxn],ans[maxn],query[maxn],cnt;
bool vis[maxn],flag[maxn],pd[maxn],bj[maxn];
struct edge
int fr,to;
e[maxn];
int read(void)
char ch=getchar();
int x=0;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9')
x=x*10+ch-'0';
ch=getchar();
return x;
void connect(int x,int y)
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
void connect1(int x,int y)
w++;
pre1[w]=last1[x];
last1[x]=w;
other1[w]=y;
void pre_bfs(void)
int h=1,t=1;
vis[1]=1;que[1]=1;
while (h<=t)
int u=que[h];h++;
for (int p=last[u];p;p=pre[p])
int v=other[p];
if (vis[v]) continue;
dis[v]=dis[u]+1;
que[++t]=v;
vis[v]=1;
void bfs(void)
memset(vis,0,sizeof vis);
vis[1]=1;que[1]=1;
int h=1,t=1;
while (h<=t)
int u=que[h];h++;
for (int p=last[u];p;p=pre[p])
int v=other[p];
if (dis[v]==dis[u]+1) flag[p/2]=1;
if (vis[v]) continue;
que[++t]=v;
vis[v]=1;
void dfs(int u)
cnt++;bj[u]=1;
for (int p=last1[u];p;p=pre1[p])
int v=other1[p];
if (bj[v]) continue;
dfs(v);
int main()
//scanf("%d%d%d",&n,&m,&q);
n=read();m=read();q=read();
for (int i=1;i<=m;i++)
int a,b;
//scanf("%d%d",&a,&b);
a=read();b=read();
e[i].fr=a;e[i].to=b;
connect(a,b);connect(b,a);
pre_bfs();
bfs();
for (int i=1;i<=q;i++)
int a;
//scanf("%d",&a);
a=read();
pd[a]=1;query[i]=a;
for (int i=1;i<=m;i++)
if (dis[e[i].fr]>dis[e[i].to]) swap(e[i].fr,e[i].to);
bj[1]=1;cnt=1;
for (int i=1;i<=m;i++)
if (!pd[i]&&flag[i])
if (bj[e[i].fr]&&bj[e[i].to]) continue;
connect1(e[i].fr,e[i].to);
if (bj[e[i].fr]) dfs(e[i].to);
ans[q]=n-cnt;
for (int i=q-1;i>=1;i--)
int num=query[i+1];
if ((!(bj[e[num].fr]&&bj[e[num].to]))&&flag[num]) connect1(e[num].fr,e[num].to);
if (bj[e[num].fr]&&flag[num]&&!bj[e[num].to]) dfs(e[num].to);
ans[i]=n-cnt;
for (int i=1;i<=q;i++) printf("%d\\n",ans[i]);
return 0;
以上是关于洛谷 1710的主要内容,如果未能解决你的问题,请参考以下文章