洛谷 1710

来源:互联网 发布:教父刀数据 编辑:程序博客网 时间:2024/05/19 03:25

   这道题是一道图论题,题目的意思是每次删除一条边,询问当前有多少点与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 400005int 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;    }


0 0
原创粉丝点击