POJ3694 e-DCC+LCA

xg,卡时间过的

题意

  给了一张n个点m个边的无向图,Q个操作,第i次操作插入边x,y。对于每次插入边,输出桥的个数。

思路  

  tarjan+缩点后,形成一个树,桥的个数即为点的个数cnt-1.

  对树进行倍增预处理。

  每次操作插入x,y点后,log查找到x和y的lca,把x,y到lca路径上的点进行标记,每标记了一个未被标记的点,cnt--。

  

 #include <iostream>
 #include <cmath>
 #include <cstdio>
 #include <cstring>
 #include <string>
 #include <map>
 #include <iomanip>
 #include <algorithm>
 #include <queue>
 #include <stack>
 #include <set>
 #include <vector> 

#define bug cout<<"--------------"<<endl
#define sp ' '
using namespace std;
typedef long long ll;

const int maxn = 1e5+10;
const int SIZE = 4e5+10;
int tot = 0;
int head[SIZE],ver[SIZE],nextt[SIZE];
void add(int x,int y)
{
    ver[++tot] = y,nextt[tot] = head[x] , head[x] = tot;
}
int n,m,num,t;
int dfn[maxn],low[maxn],bridge[SIZE];
void tarjan(int x,int in_edge)
{
    dfn[x] = low[x] = ++num;
    for(int i = head[x];i;i = nextt[i]){
        int y = ver[i];
        if(!dfn[y]){
            tarjan(y,i);
            low[x] = min(low[x],low[y]);
            if(low[y] > dfn[x])
                bridge[i] = bridge[i^1] = 1;
             //que.push(make_pair(min(i,i^1),max(i,i^1)));
        }
        else if(i!=(in_edge^1)) 
            low[x] = min(low[x],dfn[y]);
    }
}
int c[maxn],dcc;
void dfsc(int x)
{
    c[x] = dcc;
    for(int i = head[x];i;i = nextt[i]){
        int y = ver[i];
        if(c[y] || bridge[i]) continue;
        dfsc(y);
    }
}
int tc = 0;
int hc[SIZE],vc[SIZE],nc[SIZE];
void addc(int x,int y)
{
    vc[++tc] = y,nc[tc] = hc[x] , hc[x] = tc;
}
int d[maxn],f[maxn][30],fa[maxn];
void bfs(){
    queue<int> que;
    que.push(1);
    d[1] = 1;
    while(!que.empty()){
        int x = que.front();
        que.pop();
        for(int i = hc[x]; i; i = nc[i]){
            //.......
            
            int y = vc[i];
            
            if(d[y]) continue;
            fa[y] = x;
            //dist[y] = dist[x] + edge[i];
            d[y] = d[x] + 1;
            f[y][0] = x;
            for(int j = 1; j <= t;j++){
                f[y][j] = f[f[y][j-1]][j-1];
            }
            que.push(y);
        }
    }
}
int lca(int x, int y){
    if(d[x] > d[y]) swap(x,y);
    for(int i = t;i >= 0;i--){
        if(d[f[y][i]] >= d[x]) y = f[y][i];
    }
    if(x == y) return x;
    for(int i = t;i >= 0;i--){
        if(f[x][i] != f[y][i]){
            x = f[x][i];
            y = f[y][i];
        }
    }
    return f[x][0];
} 
int vis[maxn];

void clearr()
{
    num = 0;
    memset(head,0,sizeof(head));
    tot = 1;
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(bridge,0,sizeof(bridge));
    dcc = 0;
    memset(c,0,sizeof(c));
    memset(d,0,sizeof(d));
    memset(f,0,sizeof(f));
    memset(hc,0,sizeof(hc));
    tc = 0;
    memset(head,0,sizeof(head));
    memset(vis,0,sizeof(vis));
/*    for(int i=1;i<=n;++i){
        vis[i].clear();
    }
*/
}
int main()
{
   // freopen("input.txt", "r", stdin);
    int casee = 0;
    while(scanf("%d%d",&n,&m)){
        if(n == 0 && m == 0) break;
        clearr();
        for(int i = 1;i <=m ; ++i){
            int x, y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }

        for(int i = 1; i <= n;++i){
            if(!dfn[i]) tarjan(i,0);
        }
        for(int i = 1;i <= n;++i){
            if(!c[i]){
                ++dcc;
                dfsc(i);
            }
        }
        for(int i = 2;i <= tot;i=i+2){
            int x = ver[i],y = ver[i^1];
            if(c[x] == c[y]) continue;        
            addc(c[y],c[x]);
            addc(c[x],c[y]);
        } 
        //bian:tc,point:dcc
        t = log(dcc)/log(2) + 1;
        bfs();
        int ans = dcc - 1;
        //cout<<dcc<<sp<<tc<<endl;
        int Q;
        scanf("%d",&Q);
        printf("Case %d:\n",++casee );
        while(Q--){
            int x,y;
            scanf("%d%d",&x,&y);
            if(c[x] == c[y]) {
                printf("%d\n",ans);
            }
            else {
                int L = lca(c[x],c[y]);
                int a = c[x],b = c[y];
                int pos = a;

                while(pos != L){
                    if(vis[pos] == 0){
                        vis[pos] = 1;
                        ans--;
                    }
                    pos = fa[pos];
                }
                pos = b;
                while(pos != L){
                   // cout<<pos<<endl;
                    if(vis[pos] == 0){
                        vis[pos] = 1;
                        ans--;
                    }
                    pos = fa[pos];
                }
                printf("%d\n",ans );                
            }

        } printf("\n");

    }
}

 

posted @ 2020-08-22 17:15  阿斯水生产线  阅读(69)  评论(0编辑  收藏  举报