zoukankan      html  css  js  c++  java
  • bzoj2125 最短路

    https://www.lydsy.com/JudgeOnline/problem.php?id=2125

    http://www.tsinsen.com/ViewGProblem.html?gpid=-1000001268

    题解

    貌似还有一种仙人掌圆方树,跟点双圆方树区别不大,暂时不清楚有什么本质上的区别(貌似写起来容易?);以下用点双圆方树

    建圆方树,当成以dfs起始点(圆点)为根的有根树,方点到其圆点父亲的边权设为0,圆点到其方点父亲的边权设为圆点到其父亲的父亲(是圆点)在原图上的最短距离(可以预处理每个环上的前缀和方便求区间和)(话说我发现自己根本不会维护这个环...研究了一段时间有了一个可行做法:首先tarjan时候确定一个点双时弹出来的边就是点双内边,如果是仙人掌的话,若当前节点是u,可以发现是按照(v,u),(*,v),..,(u,*)的顺序;如果点双内有超过1条边,说明这个点双不是两点一线/单点(然而我并不清楚具体是怎样的?),是环;求出每个环的长度;考虑求出数组s,其中s[i]表示i点所在环的“根”(即环中在圆方树上深度最小的点)在环上顺时针/逆时针(就是一个环要同一个方向)走到i点的距离;割点在多个点双中,怎么办?设该点为u,考虑在其各个子节点(方点)代表的环中,s[u]=0,因此直接定义割点u属于的环是它父亲节点代表的环;查询距离的时候,特判掉割点)

    对于询问,如果两点lca是圆点,直接输出两点在树上距离即可

    如果两点lca是方点,“题解”里面有讲

    错误记录:边数开小了。注意仙人掌的边数范围是[n-1,2*n-2](n是点数)

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<vector>
      5 #include<cassert>
      6 using namespace std;
      7 #define fi first
      8 #define se second
      9 #define mp make_pair
     10 #define pb push_back
     11 typedef long long ll;
     12 typedef unsigned long long ull;
     13 #define int ll
     14 struct E
     15 {
     16     int f,to,nxt,d;
     17 };
     18 int n,m,qq;
     19 int s[20010];//维护从i所在环的"起点"到i的距离
     20 int len[20010];//表示第i个环的长度
     21 namespace T
     22 {
     23 
     24 E e[40100];
     25 int f1[20100],ne=1;
     26 void me(int x,int y,int z)
     27 {
     28     //printf("at%lld %lld %lld
    ",x,y,z);
     29     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].f=x;e[ne].d=z;
     30     e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;e[ne].f=y;e[ne].d=z;
     31 }
     32 int anc[20010][16],l2n=15,dd[20010][16],dep[20010];
     33 void dfs(int u,int fa)
     34 {
     35     int i;
     36     anc[u][0]=fa;
     37     for(i=1;i<=l2n;++i)
     38     {
     39         anc[u][i]=anc[anc[u][i-1]][i-1];
     40         dd[u][i]=dd[u][i-1]+dd[anc[u][i-1]][i-1];
     41     }
     42     for(int k=f1[u];k;k=e[k].nxt)
     43         if(e[k].to!=fa)
     44         {
     45             dep[e[k].to]=dep[u]+1;
     46             dd[e[k].to][0]=e[k].d;
     47             dfs(e[k].to,u);
     48         }
     49 }
     50 int getcircledis(int x,int y)//保证x,y在同一个点双内,求两点间距离
     51 //如果满足这个条件,那么要么x,y深度相等,要么一个是另一个的爷爷
     52 {
     53     if(x==y)    return 0;
     54     if(dep[x]!=dep[y])
     55     {
     56         //puts("type1");
     57         if(dep[x]<dep[y])    swap(x,y);
     58         assert(anc[x][1]==y);
     59         return min(s[x],len[anc[x][0]-n]-s[x]);
     60     }
     61     else
     62     {
     63         int an1=s[x]-s[y],an2=s[y]-s[x];
     64         if(an1<0)    an1+=len[anc[x][0]-n];
     65         if(an2<0)    an2+=len[anc[x][0]-n];
     66         return min(an1,an2);
     67     }
     68 }
     69 int calc(int x,int y)
     70 {
     71     if(dep[x]<dep[y])    swap(x,y);
     72     int t=dep[x]-dep[y],an=0,i;
     73     for(i=l2n;i>=0;--i)
     74         if(t&(1<<i))
     75         {
     76             an+=dd[x][i];
     77             x=anc[x][i];
     78         }
     79     if(x==y)    return an;
     80     //printf("1t%lld %lld
    ",x,y);
     81     for(i=l2n;i>=0;--i)
     82         if(anc[x][i]!=anc[y][i])
     83         {
     84             an+=dd[x][i];an+=dd[y][i];
     85             //printf("9t%lld %lld
    ",dd[x][i],dd[y][i]);
     86             x=anc[x][i];y=anc[y][i];
     87         }
     88     an+=anc[x][0]>n?getcircledis(x,y):(dd[x][0]+dd[y][0]);
     89     return an;
     90 }
     91 
     92 }
     93 namespace G
     94 {
     95 
     96 E e[40100];
     97 int f1[10100],ne=1;
     98 void me(int x,int y,int z)
     99 {
    100     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;e[ne].f=x;
    101     e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;e[ne].d=z;e[ne].f=y;
    102 }
    103 int st[40010];int tp;
    104 int dfn[10100],dfc,cnt;//bno[10100],cnt;
    105 int tmp[40010],tlen;
    106 int dfs(int u,int lst)
    107 {
    108     int i,k,v,lowu=dfn[u]=++dfc,lowv;
    109     for(k=f1[u];k;k=e[k].nxt)
    110     {
    111         v=e[k].to;
    112         if(!dfn[v])
    113         {
    114             st[++tp]=k;//++chi;
    115             lowv=dfs(v,k);lowu=min(lowu,lowv);
    116             if(lowv>=dfn[u])
    117             {
    118                 ++cnt;
    119                 tlen=0;
    120                 while(st[tp]!=k)    tmp[++tlen]=st[tp--];
    121                 tmp[++tlen]=st[tp--];
    122                 //printf("1t%lld %lld
    ",u,tlen);
    123                 int k;
    124                 if(tlen>1)
    125                 {
    126                     s[u]=0;
    127                     for(i=1;i<=tlen;++i)
    128                     {
    129                         k=tmp[i];
    130                         s[e[k].f]=s[e[k].to]+e[k].d;
    131                     }
    132                     len[cnt]=s[u];
    133                     for(i=1;i<tlen;++i)
    134                     {
    135                         k=tmp[i];
    136                         T::me(n+cnt,e[k].f,min(s[e[k].f],
    137                             len[cnt]-s[e[k].f]));
    138                     }
    139                     T::me(n+cnt,u,0);
    140                 }
    141                 else
    142                 {
    143                     k=tmp[1];
    144                     s[e[k].to]=e[k].d;
    145                     len[cnt]=2*s[e[k].to];
    146                     T::me(n+cnt,u,e[k].d);
    147                     T::me(n+cnt,e[k].to,0);
    148                 }
    149             }
    150         }
    151         else if(dfn[v]<dfn[u]&&k!=(lst^1))
    152         {
    153             st[++tp]=k;
    154             lowu=min(lowu,dfn[v]);
    155         }
    156     }
    157     return lowu;
    158 }
    159 void work()
    160 {
    161     int i;
    162     dfs(1,0);
    163     T::dfs(1,0);
    164 }
    165 
    166 }
    167 signed main()
    168 {
    169     int i,x,y,z;
    170     scanf("%lld%lld%lld",&n,&m,&qq);
    171     for(i=1;i<=m;++i)
    172     {
    173         scanf("%lld%lld%lld",&x,&y,&z);
    174         G::me(x,y,z);
    175     }
    176     G::work();
    177     //printf("at%lld
    ",G::tp);
    178     /*
    179     for(i=1;i<=n;++i)
    180         printf("1t%lld
    ",s[i]);
    181     for(i=1;i<=G::cnt;++i)
    182         printf("2t%lld
    ",len[i]);
    183     while(1)
    184     {
    185         int a,b;
    186         scanf("%lld%lld",&a,&b);
    187         printf("%lld
    ",T::getcircledis(a,b));
    188     }
    189     */
    190     while(qq--)
    191     {
    192         scanf("%lld%lld",&x,&y);
    193         printf("%lld
    ",T::calc(x,y));
    194     }
    195     return 0;
    196 }
    View Code

    数据生成器(只能生成每个点、边都仅在一个环上的仙人掌)

    from random import *
    circle_num=50
    n0=0
    cir=[[] for i in range(10000)]
    cirlen=[0]*1000
    e=[]
    ld=1
    rd=500
    for i in range(circle_num):
        cirlen[i]=randint(1,50)
        for j in range(cirlen[i]):
            n0+=1
            cir[i].append(n0)
        #print('t1',n0)
        for j in range(cirlen[i]-1):
            e.append([cir[i][j],cir[i][j+1],randint(ld,rd)])
        e.append([cir[i][0],cir[i][cirlen[i]-1],randint(ld,rd)])
        #print(e)
        #print(cir)
    for i in range(1,circle_num):
        fa=randint(0,i-1)
        e.append([cir[fa][randint(0,cirlen[fa]-1)],cir[i][randint(0,cirlen[i]-1)],randint(ld,rd)])
    qq=5000
    print(n0,len(e),qq)
    for i in e:
        print(i[0],i[1],i[2])
    for i in range(qq):
        print(randint(1,n0),randint(1,n0))
    View Code
  • 相关阅读:
    OpenVAS安装过程
    网络攻防环境搭建
    kali linux 安装过程
    20159217《网络攻防实践》第三周学习总结
    网络攻防实践第二周学习总结
    移动平台课程总结
    Android实践项目汇报
    性能测试四十六:Linux 从网卡模拟延时和丢包的实现
    性能测试四十五:性能测试策略
    性能测试四十四:性能优化思路
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9873625.html
Copyright © 2011-2022 走看看