【HDU】3686 Traffic Real Time Query System

题目描述:

 

 题意:给你一张图,再给你几对边,问这几对边想要互达必须经过的的点有多少。

思路分析:其实之前lin大佬讲过一道类似的题压力,题意都差不多,只是那道题问的是每个点被当做必经点的次数。而这道题问的是每对边必经点的数量。既然已经和之前做的一道题联系了起来,就当然要用到那道题的方法了,我们在原图的基础上建一个圆方树,再对每对点跑LCA就可以了,现在的问题是,有了lca后应该如何统计答案,我们要的只是从lca分别到两个点(设为x,y)的路径上的圆点的数量,但lca初始化过程中初始化出来的depth数组同时记录了圆点和方点的数量,其实我们只需将depth[x]和depth[y]的和减去2倍的depth[lca]再除以二向下取证就行了,因为为在路径上圆点和方点一定是交错出现的,以样例为例:

在图中6,7号为方点,其余为圆点,假设我们想求2,4间必通点的数量,depth[2]=3,depth[4]=5,depth[lca]=depth[6]=2;则答案为(3+5-2*2)/2-1=1。

之后就是要注意题目中最后给的是边,我们将每条边两个点四种情况分别求一遍,取一个最大值即可。

这道题调试比较恶心,但想出思路后应该就比较简单了。

上代码:

 

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<stack>
  5 #include<vector>
  6 using namespace std;
  7 const int N=1e5+10;
  8 vector<int>edge1[N];//用向量存两个图 
  9 vector<int>edge2[N];
 10 int dfn[N],low[N],dfn_cnt,scc_cnt,a[N],b[N];
 11 stack<int>sta;
 12 int n,m;
 13 void tarjan(int x,int fa){  //建圆方图部分 
 14     low[x]=dfn[x]=++dfn_cnt;
 15     sta.push(x);
 16     for(int i=0;i<edge1[x].size();++i){
 17         int v=edge1[x][i];
 18         if(!dfn[v]){
 19             tarjan(v,x);
 20             low[x]=min(low[x],low[v]);
 21             if(low[v]>=dfn[x]){
 22                 scc_cnt++;
 23                 int a;
 24                 do{
 25                     a=sta.top();
 26                     sta.pop();
 27                     edge2[a].push_back(scc_cnt);
 28                     edge2[scc_cnt].push_back(a);
 29                 }while(a!=v);
 30                 edge2[x].push_back(scc_cnt);
 31                 edge2[scc_cnt].push_back(x);
 32             }
 33         }
 34         else if(v!=fa)
 35             low[x]=min(low[x],dfn[v]);
 36     }
 37 }
 38 int p[N][21],fa[N],depth[N];
 39 void dfs(int x,int pa){  //求LCA部分 
 40     p[x][0]=fa[x];
 41     depth[x]=depth[fa[x]]+1;
 42     for(int j=0;p[x][j]!=0;++j)
 43         p[x][j+1]=p[p[x][j]][j];
 44     for(int i=0;i<edge2[x].size();++i){
 45         int v=edge2[x][i];
 46         if(v==pa) continue;
 47         fa[v]=x;
 48         dfs(v,x);
 49     }
 50 }
 51 int lca(int u,int v){
 52     if(depth[u]<depth[v]) swap(u,v);
 53     int d=depth[u]-depth[v];
 54     for(int j=0;d;d>>=1,j++){
 55         if(d&1) u=p[u][j];
 56     }
 57     if(u==v) return v;
 58     for(int j=20;~j;--j){
 59         if(p[u][j]!=p[v][j]){
 60             u=p[u][j];v=p[v][j];
 61         }
 62     }
 63     return fa[u];
 64 }
 65 void Init(int n){  //多组数据初始化 
 66     dfn_cnt=scc_cnt=0;
 67     for(int i=1;i<=n*2;++i){
 68         edge1[i].clear();
 69         edge2[i].clear();
 70     }
 71     memset(p,0,sizeof(p));
 72     memset(depth,0,sizeof(depth));
 73     memset(fa,0,sizeof(fa));
 74     memset(dfn,0,sizeof(dfn));
 75     memset(low,0,sizeof(low));
 76     while(!sta.empty()) sta.pop();
 77 }
 78 int cal(int x,int y){
 79     if(x==y) return 0;
 80     return (depth[x]+depth[y]-2*depth[lca(x,y)])/2-1;
 81 }
 82 int main(){
 83     //freopen("in.txt","r",stdin);
 84     while(scanf("%d%d",&n,&m)==2&&n&&m){
 85         Init(n);
 86         scc_cnt=n;
 87         for(int i=1;i<=m;++i){
 88             int x,y;
 89             scanf("%d%d",&x,&y);
 90             a[i]=x;b[i]=y;   //存每条边上的点,之后要用到 
 91             edge1[x].push_back(y);
 92             edge1[y].push_back(x);
 93         }
 94         for(int i=1;i<=n;++i)  //注意图可能不连通 
 95             if(!dfn[i])
 96                 tarjan(i,-1);
 97         for(int i=1;i<=scc_cnt;++i)
 98             if(!depth[i]) dfs(i,-1);
 99         int t;
100         scanf("%d",&t);
101         while(t--){
102             int x,y;
103             int ans=0;
104             scanf("%d%d",&x,&y);//计算答案 
105             ans=max(max(cal(a[x],b[x]),cal(a[x],b[y])),max(cal(a[y],b[x]),cal(a[y],b[y])));
106             printf("%d\n",ans);
107         }
108     }
109     return 0;
110 }
View Code

 

posted @ 2020-05-07 11:34  19502-李嘉豪  阅读(162)  评论(0编辑  收藏  举报