• [NEERC2007][SHOI2008]Cactus Reloaded


    题目大意:
      给你一个仙人掌,求图中相距最远的点对之间的距离。

    思路:
      Tarjan+DP。
      我们先考虑一个树的情况。
      设用far[u]表示点u出发到其子树中叶子节点的最大距离,若v为u的子结点,很显然far[u]=max{far[v]}+1。
      而对于经过点u的简单路径,最长的一条肯定是max{far[v]+far[w]+2},且u≠w。
      很显然我们只需要DFS一遍,然后随便转移即可。
      考虑一下仙人掌和树有什么不同。
      很显然仙人掌就是在一棵树上加了几条边,使得图中出现了一些环,而且不会有边同时出现在两个环中。
      我们不妨先把原图的环去掉某一个边,使得剩下的图是一棵树,很容易处理出树上的情况。
      处理到当前环中最后一条边时,再单独对这个环进行DP。
      考虑这个环上的每一棵外向树,设u和v是这个环上的两个结点,那么far[u]+far[v]+dis(u,v)就是一个可能的答案。
      如何让这个答案最大化?
      对于每一个点u,我们可以枚举每一个v来得到一个可能的答案,而要让答案尽可能大,似乎可以用单调队列来转移。
      但唯一的问题是,现在u和v是再一个环上,他们的距离是不会单调递增的,也就是说你按顺序枚举每一个点,可能先越来越远再越来越近。
      对于这种情况,我们把环复制一遍来转移,维护队列的时候要判断一下当前待更新的点u和用来更新的点v距离是不是超过环长的一半。
      最后再更新一下环上高度最高的点对应的far值。
      设环的大小为size,最高点为top,那么far[top]=max(far[top],max{far[v]+dis(top,v)})。
      这时候要注意一下,前面DFS(Tarjan)里面,far的转移要判断一下,low[v]是不是大于等于dfn[u],如果不是,说明现在是在环上。
      所以不能直接更新,不然后面环上DP可能会重复。

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<vector>
     5 inline int getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register int x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 const int N=50001;
    13 std::vector<int> e[N];
    14 int far[N],par[N],ans;
    15 inline void add_edge(const int &u,const int &v) {
    16     e[u].push_back(v);
    17     e[v].push_back(u);
    18 }
    19 inline void dp(const int &top,const int &end,const int &size) {
    20     static int cir[N*2];
    21     static std::deque<int> q;
    22     for(register int i=size,v=end;i;i--) {
    23         cir[size+i]=cir[i]=far[v];
    24         v=par[v];
    25     }
    26     q.push_back(1);
    27     for(register int i=2;i<=size*2;i++) {
    28         if(i-q.front()>size/2) q.pop_front();
    29         ans=std::max(ans,cir[i]+cir[q.front()]+i-q.front());
    30         while(!q.empty()&&cir[q.back()]-q.back()<=cir[i]-i) q.pop_back();
    31         q.push_back(i);
    32     }
    33     q.clear();
    34     for(register int i=2;i<=size;i++) {
    35         far[top]=std::max(far[top],cir[i]+std::min(i-1,size-i+1));
    36     }
    37 }
    38 void tarjan(const int &x,const int &par) {
    39     static int low[N],dfn[N],dep[N],cnt;
    40     ::par[x]=par;
    41     dep[x]=dep[par]+1;
    42     low[x]=dfn[x]=++cnt;
    43     for(unsigned i=0;i<e[x].size();i++) {
    44         const int &y=e[x][i];
    45         if(y==par) continue;
    46         if(!dfn[y]) {
    47             tarjan(y,x);
    48             low[x]=std::min(low[x],low[y]);
    49         } else {
    50             low[x]=std::min(low[x],dfn[y]);
    51         }
    52         if(dfn[x]<low[y]) {
    53             ans=std::max(ans,far[x]+far[y]+1);
    54             far[x]=std::max(far[x],far[y]+1);
    55         }
    56     }
    57     for(register unsigned i=0;i<e[x].size();i++) {
    58         const int &y=e[x][i];
    59         if(x!=::par[y]&&dfn[x]<dfn[y]) {
    60             dp(x,y,dep[y]-dep[x]+1);
    61         }
    62     }
    63 }
    64 int main() {
    65     getint();
    66     for(register int m=getint();m;m--) {
    67         for(register int k=getint(),u=getint();--k;) {
    68             const int v=getint();
    69             add_edge(u,v);
    70             u=v;
    71         }
    72     }
    73     tarjan(1,0);
    74     printf("%d
    ",ans);
    75     return 0;
    76 }
  • 相关阅读:
    计算机三级数据库-指导
    spring导入约束
    hibernater获取session时org.hibernate.service.spi.ServiceException错误
    springxml配置注入报错
    右键复制类的完整路径
    关于实体里的toString方法
    idea创建web项目环境
    框架快速找类
    如何在scdn博客里搜索自己博客文章
    永久消除自动产生的QQPCMgr
  • 原文地址:https://www.cnblogs.com/skylee03/p/8073818.html
Copyright © 2020-2023  润新知