POJ3694 Network 边双缩点+LCA+并查集

辣鸡错误:把dfs和ldfs搞混。。。QAQ


 

题意:给定一个无向图,然后查询q次,求每次查询就在图上增加一条边,求剩余割边的个数。

先把边双缩点,然后预处理出LCA的倍增数组;

然后加边时,从u往上跳,把所有u到LCA(u,v)路径上割边去掉,即 --ans;v同理;

而向上跳的时候可以用并查集,把已经去掉的边,用路径压缩忽略掉,会往上跳的更快些。

memset记得写全,不然。。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #define R register int
 6 const int N=100010;
 7 using namespace std;
 8 inline int g() {
 9     R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
10     do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
11 }
12 int n,m,cc,cnt,num,dcc,T;
13 int vr[N<<2],nxt[N<<2],fir[N],dfn[N],low[N],c[N],d[N],f[N][18],fa[N];
14 bool bge[N<<2];
15 inline void add(int u,int v) {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
16 void tarjan(int u,int E) {
17     dfn[u]=low[u]=++num;
18     for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
19         if(!dfn[v]) {
20             tarjan(v,i);
21             low[u]=min(low[u],low[v]);
22             if(low[v]>dfn[u]) bge[i]=bge[i^1]=true;
23         } else if(i!=(E^1))low[u]=min(low[u],low[v]);
24     }
25 }
26 void dfs(int u) {
27     c[u]=dcc;
28     for(R i=fir[u];i;i=nxt[i]) if(!bge[i]&&!c[vr[i]]) dfs(vr[i]);
29 }
30 int ff[N],vv[N<<2],nn[N<<2],tc=1;
31 inline void addc(int u,int v) {vv[++tc]=v,nn[tc]=ff[u],ff[u]=tc;}
32 inline void solve() {
33     for(R i=2;i<=cnt;++i) {
34         R u=vr[i^1],v=vr[i];
35         if(c[u]==c[v]) continue;
36         addc(c[u],c[v]);
37     }
38 }
39 void ldfs(int u) {
40     for(R i=ff[u];i;i=nn[i]) { R v=vv[i];
41         if(d[v]) continue;
42         f[v][0]=u,d[v]=d[u]+1; R p=u;
43         for(R j=0;f[p][j];++j) f[v][j+1]=f[p][j],p=f[p][j];
44         ldfs(v);
45     }
46 }
47 inline int lca(int u,int v) {
48     if(d[u]<d[v]) swap(u,v); R lim=log2(d[u])+1;
49     for(R i=lim;i>=0;--i) if(d[f[u][i]]>=d[v]) u=f[u][i];
50     if(u==v) return u;
51     for(R i=lim;i>=0;--i) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
52     return f[u][0];
53 }
54 int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
55 signed main() {
56     while(n=g(),m=g(),m||n) { cnt=1;tc=1;num=dcc=cc=0;
57         memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(nxt,0,sizeof(nxt));memset(fir,0,sizeof(fir));
58         memset(bge,false,sizeof(bge));memset(nn,0,sizeof(nn));memset(ff,0,sizeof(ff)); memset(c,0,sizeof(c));memset(f,0,sizeof(f));
59         for(R i=1,u,v;i<=m;++i) u=g(),v=g(),add(u,v),add(v,u);
60         for(R i=1;i<=n;++i) if(!dfn[i]) tarjan(i,0);
61         for(R i=1;i<=n;++i) if(!c[i]) ++dcc,dfs(i);
62         for(R i=1;i<=n;++i) fa[i]=i;
63         solve(); d[1]=1;ldfs(1); R q=g(),ans=dcc-1; 
64         printf("Case %d:\n",++T);
65         while(q--) {
66             R u=g(),v=g();
67             u=c[u],v=c[v]; R L=lca(u,v); //cout<<L<<'\n';
68             u=getf(u),v=getf(v);
69             while(d[u]>d[L]) fa[u]=f[u][0],--ans,u=getf(u);
70             while(d[v]>d[L]) fa[v]=f[v][0],--ans,v=getf(v);
71             printf("%d\n",ans);        
72         } putchar('\n');
73     }
74 }

2019.04.12

 

转载于:https://www.cnblogs.com/Jackpei/p/10695766.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值