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"); } }