洛谷 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的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1162(自我感觉思路还算巧妙的一道题)

洛谷 P2764 最小路径覆盖问题匈牙利算法

洛谷 P2770 航空路线问题最大费用最大流

[洛谷U22156]未曾届到游览(矩阵树定理)

洛谷 - P1989 无向图三元环计数(思维建图)

缩点(洛谷3387)——不会写DP 的我只好来了个SPFA