zoukankan      html  css  js  c++  java
  • [BZOJ2125]最短路(圆方树DP)

    题意:仙人掌图最短路。

    算法:圆方树DP,$O(nlog n+Qlog n)$

    首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在圆方树上u-v的路径上的所有边权之和,加上每个环(方点)中连出去的两个点的最短距离。

    现在问题就是:如何求出环上两个点的最短路径。考虑这样设定边权,首先显然圆圆边的边权就是原图的边权,然后设一个环在搜索树中深度最小的点为这个环的根,则方圆边的边权是环的根到这个点的最短距离,这个可以在Tarjan的时候直接求出。

    但是圆方树问题通常需要在LCA处分圆方点讨论。首先如果LCA是圆点,那么直接做即可。如果是方点,就需要决定要不要走环的另一侧,这个同样直接讨论即可。

    具体见代码,感觉思路还是比较清晰的。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=l; i<=r; i++)
     4 using namespace std;
     5 
     6 const int N=20010;
     7 int n,m,Q,u,v,w,tot,tim,top,dep[N],len[N],type[N],stk[N];
     8 int dfn[N],low[N],dis[N],lst[N],fa[N][16],sm[N][16];
     9 
    10 struct E{
    11     int cnt,h[N],to[N<<1],nxt[N<<1],val[N<<1];
    12     void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    13 }G,G1;
    14 
    15 void work(int x,int k){
    16     tot++; int t; len[tot]=dis[stk[top]]-dis[x]+lst[stk[top]];
    17     do{
    18         t=stk[top--];
    19         int A=dis[t]-dis[x],B=len[tot]-A;
    20         G1.add(tot,t,min(A,B)); type[t]=(A<=B);
    21     }while (t!=k);
    22     G1.add(x,tot,0);
    23 }
    24 
    25 void Tarjan(int x,int pre){
    26     //printf("%d
    ",x);
    27     dfn[x]=low[x]=++tim; stk[++top]=x;
    28     for (int i=G.h[x],k; i; i=G.nxt[i]){
    29         if ((k=G.to[i])==pre) continue;
    30         if (!dfn[k]){
    31             dis[k]=dis[x]+G.val[i]; Tarjan(k,x);
    32             //printf("%d %d %d %d
    ",x,k,dfn[x],low[k]);
    33             if (low[k]>dfn[x]) top--,G1.add(x,k,G.val[i]);
    34             else if (low[k]==dfn[x]) work(x,k);
    35             low[x]=min(low[x],low[k]);
    36         }else low[x]=min(low[x],dfn[k]),lst[x]=G.val[i];
    37     }
    38 }
    39 
    40 void dfs(int x,int pre){
    41     for (int i=G1.h[x],k; i; i=G1.nxt[i])
    42         fa[k=G1.to[i]][0]=x,dep[k]=dep[x]+1,sm[k][0]=G1.val[i],dfs(k,x);
    43 }
    44 
    45 int lca(int u,int v){
    46     if (dep[u]<dep[v]) swap(u,v);
    47     int t=dep[u]-dep[v],res=0;
    48     for (int i=15; ~i; i--) if (t&(1<<i)) res+=sm[u][i],u=fa[u][i];
    49     if (u==v) return res;
    50     for (int i=15; ~i; i--) if (fa[u][i]!=fa[v][i])
    51         res+=sm[u][i]+sm[v][i],u=fa[u][i],v=fa[v][i];
    52     if (fa[u][0]<=n) return sm[u][0]+sm[v][0]+res;
    53     int A=sm[u][0],B=sm[v][0],mn;
    54     if (type[u]==type[v]) mn=min(abs(A-B),len[fa[u][0]]-abs(A-B));
    55         else mn=min(A+B,len[fa[u][0]]-A-B);
    56     return res+mn;
    57 }
    58 
    59 int main(){
    60     freopen("bzoj2125.in","r",stdin);
    61     freopen("bzoj2125.out","w",stdout);
    62     scanf("%d%d%d",&n,&m,&Q); tot=n;
    63     rep(i,1,m) scanf("%d%d%d",&u,&v,&w),G.add(u,v,w),G.add(v,u,w);
    64     Tarjan(1,0); dfs(1,0);
    65     //rep(i,1,tot) printf("%d ",low[i]); puts("");
    66     rep(j,1,15) rep(i,1,tot)
    67         fa[i][j]=fa[fa[i][j-1]][j-1],sm[i][j]=sm[i][j-1]+sm[fa[i][j-1]][j-1];
    68     rep(i,1,Q) scanf("%d%d",&u,&v),printf("%d
    ",lca(u,v));
    69     return 0;
    70 }
  • 相关阅读:
    delphi7在windows server 2003企业版上不能打开项目的选项(Options)窗口的解决方法
    简单的两个字“谢谢”,会让我坚持我的写作,我也要谢谢你们
    F41GUT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
    远程桌面无法登录windows server 2003服务器
    F41GUT 安装Windows server 2003系统后无法安装显卡驱动的解决办法
    MS SQL Server 2000版在windows server 2003企业版系统上运行时造成数据库suspect的解决方法
    delphi7在windows server 2003企业版上不能打开项目的选项(Options)窗口的解决方法
    远程桌面无法登录windows server 2003服务器
    MS SQL Server 2000版在windows server 2003企业版系统上运行时造成数据库suspect的解决方法
    关于ajax 和josn
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9143979.html
Copyright © 2011-2022 走看看