zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
    107         }
    108     }
    109     return 0;
    110 }
    View Code
  • 相关阅读:
    数组
    mysql优化思路
    mysql_存储过程
    mysql_函数
    mysql_结构
    mysql_触发器
    mysql_变量
    mysql_事务
    mysql总结
    mysql备份
  • 原文地址:https://www.cnblogs.com/li-jia-hao/p/12841842.html
Copyright © 2011-2022 走看看