hdu4338 Simple Path

Everybody knows that totalfrank has absolutely no sense of direction. Getting lost in the university or nearly supermarket is very common for him. We always worry about whether he can find his way back into our sweet base whenever he goes out alone for his class. In general, if totalfrank get lost again, we need to check his starting point and destination just in order to find out where he could be (you know this task is very common for us).
Unfortunately, poor totalfrank sometimes forgot taking his mobile phone, when this situation happens, we can’t get in touch with him. But it is so lucky that totalfrank can remember places where he had gone before in his trip from his starting point and destination at this trip so that he won’t go to such place again (he can’t remember places which he had gone during his previous trip). As we are all familiar with map, we can find out which place he couldn’t be.
However, totalfrank can always get lost, doing this same boring work makes us sleepy. So we ask totalfrank for all possible starting point and destination for him, and try to find out how many places he wouldn’t be when he chooses any pair of starting point and destination. Here comes the problem, since our university’s map is so complex (there can be many buildings which can be considered as points in our university, some pair of these point has a way while others hasn’t), we need a program to help us work out this problem.

  1 #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include <string.h>
  3 #include <stdio.h>
  4 #include <math.h>
  5 #include <algorithm>
  6 const int MAXN=1e5+5;
  7 
  8 struct edge{
  9     int u,v,n;
 10 }e1[MAXN*4],e2[MAXN*4];
 11 
 12 int f1[MAXN],f2[MAXN*2],es1,es2;
 13 int n,m,q,tu,tv;
 14 
 15 void addedge1(int u,int v){    
 16     e1[es1].u=u,e1[es1].v=v,e1[es1].n=f1[u],f1[u]=es1++;
 17 }
 18 
 19 void addedge2(int u,int v){
 20     e2[es2].u=u,e2[es2].v=v,e2[es2].n=f2[u],f2[u]=es2++;
 21 }
 22 
 23 int p[MAXN*2];
 24 
 25 int find(int x){return x==p[x]?x:p[x]=find(p[x]);}
 26 
 27 void merge(int x,int y){p[find(x)]=find(y);}
 28 
 29 int sum[MAXN*2],tsum[MAXN*2],dis[MAXN];
 30 int lca_f[MAXN*4],lca_b[MAXN*4],lca_p[MAXN*2],rid;
 31 int dminv[MAXN*4][20],dminid[MAXN*4][20];
 32 
 33 void dp(int u,int f,int dd,int tot){
 34     dis[u]=dd,tsum[u]=tot+sum[u];
 35     lca_f[++rid]=u,lca_b[rid]=dd,lca_p[u]=rid;
 36     for(int i=f2[u];i!=-1;i=e2[i].n){
 37         int v=e2[i].v;
 38         if(v==f)continue;
 39         dp(v,u,dd+1,tot+sum[u]);
 40         lca_f[++rid]=u,lca_b[rid]=dd;
 41     }
 42 }
 43 
 44 void makermq(){
 45     rid=0;
 46     dp(0,-1,0,0);
 47     for(int i=1;i<=rid;i++)dminv[i][0]=lca_b[i],dminid[i][0]=i;
 48     int maxj=(int)(log(rid+1.0)/log(2.0));
 49     for(int j=1;j<=maxj;j++){
 50         int maxi=rid+1-(1<<j);
 51         for(int i=1;i<=maxi;i++){
 52             if(dminv[i][j-1]<dminv[i+(1<<(j-1))][j-1]){
 53                 dminv[i][j]=dminv[i][j-1];
 54                 dminid[i][j]=dminid[i][j-1];
 55             }else{
 56                 dminv[i][j]=dminv[i+(1<<(j-1))][j-1];
 57                 dminid[i][j]=dminid[i+(1<<(j-1))][j-1];
 58             }
 59         }
 60     }
 61 }
 62 
 63 int lca(int x,int y){
 64     if(lca_p[x]>lca_p[y])std::swap(x,y);
 65     x=lca_p[x],y=lca_p[y];
 66     int k=(int)(log(y-x+1.0)/log(2.0));
 67     int xx=dminv[x][k]<dminv[y+1-(1<<k)][k]?dminid[x][k]:dminid[y+1-(1<<k)][k];
 68     return lca_f[xx];
 69 }
 70 
 71 int dfn[MAXN],low[MAXN],cid[MAXN],stk[MAXN],col[MAXN],top,ind,cls,tmp;
 72 int cal[MAXN*2];
 73 
 74 void dfs_cutpnt(int u,int f,int root){
 75     dfn[u]=low[u]=++ind;
 76     int cnt=0;
 77     int flag=0;
 78     for(int i=f1[u];i!=-1;i=e1[i].n){
 79         int v=e1[i].v;
 80         if(v==f&&!flag){flag=1;continue;}
 81         if(!dfn[v]){
 82             cnt++;
 83             dfs_cutpnt(v,u,root);
 84             if(low[v]<low[u])low[u]=low[v];
 85             if(u==root&&cnt>1&&cid[u]==0)cid[u]=++cls,sum[cls]=1;
 86             else if(u!=root&&low[v]>=dfn[u]&&cid[u]==0)cid[u]=++cls,sum[cls]=1;
 87         }else if(dfn[v]<low[u])low[u]=dfn[v];
 88     }
 89 }
 90 
 91 void dfs_tarjan(int u,int f){
 92     low[u]=dfn[u]=++ind;
 93     stk[++top]=u;
 94     int flag=0;
 95     for(int i=f1[u];i!=-1;i=e1[i].n){
 96         int v=e1[i].v;
 97         if(v==f&&!flag){flag=1;continue;}
 98         if(!dfn[v]){
 99             dfs_tarjan(v,u);
100             if(low[v]<low[u])low[u]=low[v];
101             if(low[v]>=dfn[u]){
102                 sum[++cls]=1,col[u]=cls;
103                 do{
104                     tmp=stk[top--],col[tmp]=cls,++sum[cls];
105                     if(cid[tmp]){addedge2(cid[tmp],cls);addedge2(cls,cid[tmp]);merge(cid[tmp],cls);}
106                 }while(tmp!=v);
107                 if(cid[u]){addedge2(cid[u],cls);addedge2(cls,cid[u]);merge(cid[u],cls);}
108             }
109         }else if(dfn[v]<low[u])low[u]=dfn[v];
110     }
111 }
112 
113 int size;
114 
115 void makegraph(){
116     //找割点
117     memset(dfn,0,sizeof dfn);
118     memset(low,0,sizeof low);
119     memset(cid,0,sizeof cid);
120     cls=ind=0;
121     //找双联通分量并建图
122     for(int i=0;i<n;i++)dfs_cutpnt(i,-1,i);
123     memset(dfn,0,sizeof dfn);
124     memset(low,0,sizeof low);
125     memset(col,0,sizeof col);
126     top=ind=0;
127     for(int i=0;i<n;i++)dfs_tarjan(i,-1);
128     //将森林补成树,便于dp以及查询
129     memset(cal,0,sizeof cal);
130     for(int i=1;i<=cls;i++){
131         if(cal[find(i)]==0){
132             cal[find(i)]=1;
133             addedge2(0,i);
134         }
135     }
136 }
137 
138 int main(){
139     //freopen("test.in","r",stdin);
140     int cas=1;
141     while(scanf("%d%d",&n,&m)!=EOF){
142         memset(f1,-1,sizeof f1);
143         memset(f2,-1,sizeof f2);
144         for(int i=0;i<=2*n;i++)p[i]=i;
145         es1=es2=0;
146 
147         for(int i=0;i<m;i++){
148             scanf("%d%d",&tu,&tv);
149             addedge1(tu,tv);
150             addedge1(tv,tu);
151         }
152 
153         //转化成双联通与割点相邻的图
154         makegraph();
155         //lca转化成rmq
156         makermq();
157 
158         printf("Case #%d:\n",cas++);
159         scanf("%d",&q);
160         while(q--){
161             scanf("%d%d",&tu,&tv);
162             //起点和终点重合
163             if(tu==tv)printf("%d\n",n-1);
164             else{
165                 //如果是割点的话就一定要用割点对应的点,因为割点会被染成不同的颜色!
166                 tu=cid[tu]?cid[tu]:col[tu];
167                 tv=cid[tv]?cid[tv]:col[tv];
168                 //孤立点或者不在同一个联通块中
169                 if(tu==0||tv==0||find(tu)!=find(tv)){
170                     printf("%d\n",n);
171                 }else{
172                     int fa=lca(tu,tv);
173                     int ans=tsum[tu]+tsum[tv]-2*tsum[fa]+sum[fa];
174                     ans-=(dis[tu]+dis[tv]-2*dis[fa]);
175                     printf("%d\n",n-ans);
176                 }
177             }
178         }
179         printf("\n");
180     }
181     return 0;
182 }
View Code

 

转载于:https://www.cnblogs.com/cenariusxz/p/6598185.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值