zoukankan      html  css  js  c++  java
  • [树形dp][Tarjan][单调队列] Bzoj 1023 cactus仙人掌图

    Description

      如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌
    图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。

     

      举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6
    ,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两
    个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。显然,仙人图上的每条边,或者是这张仙
    人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最
    短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1
    ,你的任务是求出给定的仙人图的直径。

    题解

    • 如果是圆圆边的话和普通的树形dp一样
    • 对于环的话,把他拎出来单独考虑,首先要计算出这个环的贡献,然后更新环的最顶点
    • 更新的话,就这个直接拿环上的点的dp值,再计算一下这两点之间的最短路,相加后更新
    • 贡献的话,就是max(f[i]+f[j]+dis(i,j)),dis(i,j)=min(abs(deep[i]-deep[j]),size[环]-abs(deep[i]-deep[j]))
    • 可以维护一个单调队列,按照深度进栈

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N=60010;
     6 struct edge{int to,from;}e[N*8];
     7 int n,m,L,R,cnt=1,ans=1,head[N],Q[N*2],q[N*2],f[N],Fa[N],deep[N],dfn[N],low[N];
     8 void insert(int x,int y)
     9 {
    10     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
    11     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
    12 }
    13 void dp(int x,int y)
    14 {
    15     int r=0;
    16     for (int i=y;i!=x;i=Fa[i]) Q[++r]=i; Q[++r]=x;
    17     reverse(&Q[1],&Q[r+1]);
    18     for (int i=1;i<=r;i++) Q[i+r]=Q[i];
    19     L=1,R=0;
    20     for (int i=1;i<=r*2;i++)
    21     {
    22         while (L<=R&&i-q[L]>r/2) ++L;
    23         if (L<=R) ans=max(ans,f[Q[i]]+f[Q[q[L]]]+i-q[L]);
    24         while (L<=R&&f[Q[i]]-i>f[Q[q[R]]]-q[R]) R--;
    25         q[++R]=i;
    26     }
    27     for (int i=y;i!=x;i=Fa[i]) f[x]=max(f[x],f[i]+min(deep[i]-deep[x],1+deep[y]-deep[i]));
    28 }
    29 void dfs(int x,int fa)
    30 {
    31     Fa[x]=fa,dfn[x]=low[x]=++dfn[0],deep[x]=deep[fa]+1;
    32     for (int i=head[x];i;i=e[i].from) 
    33     {
    34         if (!dfn[e[i].to]) dfs(e[i].to,x),low[x]=min(low[x],low[e[i].to]); else if (e[i].to!=fa) low[x]=min(low[x],dfn[e[i].to]);
    35         if (low[e[i].to]>dfn[x]) ans=max(ans,f[x]+f[e[i].to]+1),f[x]=max(f[x],f[e[i].to]+1);
    36     }
    37     for (int i=head[x];i;i=e[i].from) if (Fa[e[i].to]!=x&&dfn[x]<dfn[e[i].to]) dp(x,e[i].to);
    38 }
    39 int main()
    40 {
    41     scanf("%d%d",&n,&m);
    42     for (int i=1,k,x,y;i<=m;i++)
    43     {
    44         scanf("%d%d",&k,&x);
    45         for (int j=1;j<k;j++) scanf("%d",&y),insert(x,y),x=y;
    46     }
    47     dfs(1,0),printf("%d",ans);
    48 }
  • 相关阅读:
    1接口编程
    EXCEL读写NPOI--导出功能
    EXCEL读写NPOI
    多条件查询
    基础数据管理
    C#经典入门第22章XML-1
    数据访问C#入门经典第21章-监控文件系统
    数据访问C#入门经典第21章-读写压缩数据
    Tensorflow笔记(基础):池化函数
    4.2 Tensorflow笔记:池化函数
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11367500.html
Copyright © 2011-2022 走看看