zoukankan      html  css  js  c++  java
  • 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II

    题目背景

    题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有。 但是实际上还是和bzoj1023是一个题目的。

    题目描述

    如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。

    输入输出格式

    输入格式:

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

    输出格式:

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


    注意直径的定义,距离定义为最小距离,直径定义为最大距离。

    然后树边普通dp,环上需要去小距离,把环倍长,每次只留下环的1/2长度的最大值进行更新即可,用单调队列维护一下。

    然后我倍长数组没开两倍调了20年...


    Code:

    #include <cstdio>
    #include <algorithm>
    using std::min;
    using std::max;
    const int N=50010;
    int head[N],to[N<<4],Next[N<<4],cnt;
    void add(int u,int v)
    {
    	to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
    }
    int n,m,s[N<<1],tot,fa[N],dfn[N],low[N],dfsclock,dp[N],ans,q[N<<1],l,r;
    void cal(int rt,int p)
    {
    	int now=p;tot=0;
    	while(now!=rt)
    	{
    		s[++tot]=now;
    		now=fa[now];
    	}s[++tot]=rt;
    	for(int i=1;i<=tot;i++) s[i+tot]=s[i];
    	tot<<=1,l=1,r=0;
    	for(int i=1;i<=tot;i++)
    	{
    		while(l<=r&&i-q[l]>tot>>2) ++l;
    		if(l<=r) ans=max(ans,dp[s[i]]+dp[s[q[l]]]+i-q[l]);
    		while(l<=r&&dp[s[i]]>=dp[s[q[r]]]+i-q[r]) --r;
    		q[++r]=i;
    	}
    	tot>>=1;
    	for(int i=1;i<=tot;i++) dp[rt]=max(dp[rt],dp[s[i]]+min(i,tot-i));
    }
    void dfs(int now)
    {
    	dfn[now]=low[now]=++dfsclock;
    	for(int v,i=head[now];i;i=Next[i])
    		if((v=to[i])!=fa[now])
    		{
    			if(!dfn[v]) fa[v]=now,dfs(v),low[now]=min(low[now],low[v]);
    			else low[now]=min(low[now],dfn[v]);
    			if(dfn[now]<low[v]) ans=max(ans,dp[v]+dp[now]+1),dp[now]=max(dp[now],dp[v]+1);
    		}
    	for(int v,i=head[now];i;i=Next[i])
    		if(fa[v=to[i]]!=now&&dfn[v]>dfn[now])
    			cal(now,v);
        ans=max(ans,dp[now]);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int k,u,v,i=1;i<=m;i++)
    	{
    		scanf("%d%d",&k,&u);
    		for(int j=1;j<k;j++)
    		{
    			scanf("%d",&v);
    			add(u,v),add(v,u);
    			u=v;
    		}
    	}
    	dfs(1);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    2018,12,25

  • 相关阅读:
    jqueryeasyui中创建复杂布局
    内表查询用到外表
    某人对为什么不搞.net,不搞web的原因
    眼睛痛的一些原因
    控件包含代码块(即 <% ... %>),因此无法修改控件集合(用户自定义控件中)
    明天留着看
    SqlServer 数据归档
    从 char 数据类型到 datetime 数据类型的转换导致 datetime 值越界。
    生成sql 脚本没有索引
    sqlserver 时间间隔
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10174884.html
Copyright © 2011-2022 走看看