zoukankan      html  css  js  c++  java
  • 【BZOJ】【1023】【SHOI2008】cactus仙人掌图

    DP+单调队列/仙人掌


      题解:http://hzwer.com/4645.html->http://z55250825.blog.163.com/blog/static/150230809201412793151890/

      QAQ了

      呃……第一次做仙人掌的题目……感觉性质还是蛮神奇的(我是不是应该先做一点环套树的题目呢?>_>)

      每个点都只会在一个简单环上,所以在dfs的时候,对于一个环,它上面的点是深度连续的一段(沿着father可以遍历这个环!),然后最后一个点再指回起始点,所以只要low改变了,就找到了一个环。。。

      判是否在环上也很好判,看下low就可以了

      简单了解了仙人掌的情况,我们来看下这道题怎么做:

      如果是一棵树的话,我们只要Tree DP就可以了……令f[i]表示以 i 为根的最长的链,子树合并的时候随便搞搞……比较简单。

      现在麻烦的是出现了环= =所以f[i]的定义本身就有些纠结……

      既然这样,那么我们就把问题分成两部分来做吧!树的部分和环的部分!

      对于树的部分……同上

      那么环的部分是什么情况呢?我们可以令f[i]表示环上这个点向外的最长链的长度(这个定义对于树的部分不冲突,所以不用分开算)然后环上的最长链就是:$ans=max{ f[i]+f[j]+min{j-i,tot-j+i} }$呃……其实意思就是找环上两条链出来,然后加上它俩直接的距离求个最大值。最后需要更新一下环的“根”节点的f[root],这时它的子树已经完全计算完毕了,那么f[root]就应该表示以它为根的最长链,那么我们就可以用环上其他点连出去的链来更新这个f[root](其实之前算环上两条链的时候有一种情况算不到,现在就是在做这个哦,这句如果不理解就忽视掉吧,不是很重要……)

     1 /**************************************************************
     2     Problem: 1023
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:212 ms
     7     Memory:9792 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1023
    11 #include<cstdio>
    12 #include<cstring>
    13 #include<cstdlib>
    14 #include<iostream>
    15 #include<algorithm>
    16 #define rep(i,n) for(int i=0;i<n;++i)
    17 #define F(i,j,n) for(int i=j;i<=n;++i)
    18 #define D(i,j,n) for(int i=j;i>=n;--i)
    19 using namespace std;
    20 typedef long long LL;
    21 inline int getint(){
    22     int v=0,r=1; char ch=getchar();
    23     for(;!isdigit(ch);ch=getchar()) if(ch=='-')r=-1;
    24     for(; isdigit(ch);ch=getchar()) v=v*10+ch-'0';
    25     return v*r;
    26 }
    27 const int N=1e5+10,INF=~0u>>2;
    28 /*********************template******************/
    29 int to[N<<2],next[N<<2],head[N],cnt;
    30 void add(int x,int y){
    31     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt;
    32     to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt;
    33 }
    34 int dfn[N],low[N],fa[N],dep[N],dfs_clock,a[N],Q[N],f[N];
    35 int n,m,ans;
    36 void dp(int root,int x){
    37     int tot=dep[x]-dep[root]+1,j=tot;
    38     for(int i=x;i!=root;i=fa[i])
    39         a[j--]=f[i];
    40     a[j]=f[root];
    41     F(i,1,tot) a[i+tot]=a[i];
    42     int l=0,r=-1;
    43     Q[++r]=1;
    44     F(i,2,tot*2){
    45         while(l<=r && i-Q[l]>tot/2) l++;
    46         ans=max(ans,a[i]+i+a[Q[l]]-Q[l]);
    47         while(l<=r && a[Q[r]]-Q[r]<a[i]-i) r--;
    48         Q[++r]=i;
    49     }
    50     F(i,2,tot)
    51         f[root]=max(f[root],a[i]+min(i-1,tot-i+1));
    52 }
    53 void dfs(int x){
    54     dfn[x]=low[x]=++dfs_clock;
    55     for(int i=head[x];i;i=next[i])
    56         if (to[i]!=fa[x]){
    57             if (!dfn[to[i]]){
    58                 fa[to[i]]=x;
    59                 dep[to[i]]=dep[x]+1;
    60                 dfs(to[i]);
    61                 low[x]=min(low[x],low[to[i]]);
    62             }else low[x]=min(low[x],dfn[to[i]]);
    63             if (dfn[x]<low[to[i]]){
    64                 ans=max(ans,f[x]+f[to[i]]+1);
    65                 f[x]=max(f[x],f[to[i]]+1);
    66             }
    67         }
    68     for(int i=head[x];i;i=next[i])
    69         if (fa[to[i]]!=x && dfn[x]<dfn[to[i]])
    70             dp(x,to[i]);
    71 }
    72 int main(){
    73 #ifndef ONLINE_JUDGE
    74     freopen("1023.in","r",stdin);
    75     freopen("std.out","w",stdout);
    76 #endif
    77     n=getint(); m=getint();
    78     F(i,1,m){
    79         int k=getint(),a=getint(),b;
    80         F(i,2,k){
    81             b=getint();
    82             add(a,b);
    83             a=b;
    84         }
    85     }
    86     dfs(1);
    87     printf("%d
    ",ans);
    88     return 0;
    89 }
    View Code

    1023: [SHOI2008]cactus仙人掌图

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 1329  Solved: 532
    [Submit][Status][Discuss]

    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,你的任务是求 出给定的仙人图的直径。

    Input

    输入的第一行包括两个整数n 和m(1≤n≤50000以及0≤m≤10000)。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。接下来一共有m行。代表m条路径。每行的开 始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数。接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两 个顶点的边。一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从3经过8,又从8返回到了3,但是我们保证所有的边都会出现在某条路径 上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。

    Output

    只需输出一个数,这个数表示仙人图的直径长度。

    Sample Input

    15 3
    9 1 2 3 4 5 6 7 8 3
    7 2 9 10 11 12 13 10
    5 2 14 9 15 10 8
    10 1
    10 1 2 3 4 5 6 7 8 9 10

    Sample Output

    9

    HINT

    对第一个样例的说明:如图,6号点和12号点的最短路径长度为8,所以这张图的直径为8。


     


    【注意】使用Pascal语言的选手请注意:你的程序在处理大数据的时候可能会出现栈溢出。如果需要调整栈空间的大小,可以在程序的开头填加一句:{$M 5000000},其中5000000即指代栈空间的大小,请根据自己的程序选择适当的数值。

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    Codeforces Gym 100571A A. Cursed Query 离线
    codeforces Gym 100500 J. Bye Bye Russia
    codeforces Gym 100500H H. ICPC Quest 水题
    codeforces Gym 100500H A. Potion of Immortality 简单DP
    Codeforces Gym 100500F Problem F. Door Lock 二分
    codeforces Gym 100500C D.Hall of Fame 排序
    spring data jpa 创建方法名进行简单查询
    Spring集成JPA提示Not an managed type
    hibernate配置文件中的catalog属性
    SonarLint插件的安装与使用
  • 原文地址:https://www.cnblogs.com/Tunix/p/4421596.html
Copyright © 2011-2022 走看看