1023: [SHOI2008]cactus仙人掌图

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 1141  Solved: 435
[Submit][Status]

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即指代栈空间的大小,请根据自己的程序选择适当的数值。

  这种仙人掌一个点可能在多个环中,所以处理起来会比较麻烦,看了网上的最长的题解http://z55250825.blog.163.com/blog/static/150230809201412793151890/,和最短的标程http://hzwer.com/4645.html才有了基本的思路。很多的类似图论题都是在tarjan内部就完成大部分的操作,而我总是指望tarjan完成之后才统一处理,这样就丢掉了很多有用的信息。

  注意,bzoj上srand(time(0))是要RE的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
#define PROB "cactus"
#define MAXN 100010
#define MAXV MAXN
#define MAXE MAXV * 2
#define INF 0x3f3f3f3f
struct edge
{
int x,y,id;
}e[MAXE];
int n,m;
int prv[MAXN];
struct Edge
{
int sp,np,val,id;
Edge *next;
}E[MAXE],*V[MAXV];
int tope;
int dfn[MAXN],dfstime=;
int ans=;
void addedge(int x,int y,int id,int z=)
{
E[++tope].np=y;
E[tope].id=id;
E[tope].sp=x;
E[tope].val=z;
E[tope].next=V[x];
V[x]=&E[tope];
}
int len[MAXN];
int arr[MAXN];
int seq[MAXN];
int vis[MAXN];
void solve(int rt,int now)
{
int tota=;
int x,i;
x=now;
while (x!=rt)
{
arr[tota++]=len[x];
x=prv[x];
}
arr[tota++]=;
for (i=;i<tota;i++)
arr[i+tota]=arr[i];
x=;
seq[]=;
int tail=,head=;
for (i=;i<tota*;i++)
{
while (i-seq[head]>tota/)head++;
ans=max(ans,arr[seq[head]]+(i-seq[head])+arr[i]);
while (tail>=head && arr[seq[tail]] + (i-seq[tail]) <=arr[i])tail--;
seq[++tail]=i;
}
}
int low[MAXN];
bool inc[MAXN];
vector<int> ptr[MAXN];
void dfs(int now,int pnt=-)
{
low[now]=dfn[now]=++dfstime;
Edge *ne;
vis[now]=;
int x=-,y=-;
int st=-,rt;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==prv[now])continue;
if (vis[ne->np]==)
{
ptr[ne->np].push_back(now);
low[now]=min(low[now],dfn[ne->np]);
}else if (!vis[ne->np])
{
prv[ne->np]=now;
dfs(ne->np,now);
low[now]=min(low[now],low[ne->np]);
}
}
for (int i=;i<ptr[now].size();i++)
{
st=ptr[now][i],rt=now;
int sizc=;
x=st;
inc[x]=true;
while (x!=rt)
{
x=prv[x];
inc[x]=true;
sizc++;
}
x=st;
int d=;
int t=;
while (x!=rt)
{
t=max(t,min(d,sizc-d)+len[x]);
d++;
x=prv[x];
}
ans=max(ans,t+len[rt]);
len[rt]=max(len[rt],t);
solve(rt,st);
}
x=y=;
if (!inc[now])
{
for (ne=V[now];ne;ne=ne->next)
{
if (dfn[ne->np]<dfn[now])continue;
if (y<len[ne->np]+)
{
y=len[ne->np]+;
if (x<y)swap(x,y);
}
}
}
if (low[now]==dfn[now])
{
if (prv[now])ans=max(ans,len[now]++len[prv[now]]);
if (prv[now])len[prv[now]]=max(len[prv[now]],len[now]+);
}
ans=max(ans,x+y);
vis[now]=;
}
int deg[MAXN];
void work()
{
int i,x,y;
for (i=;i<m;i++)
{
x=e[i].x;
y=e[i].y;
addedge(x,y,i);
addedge(y,x,i);
deg[x]++;
deg[y]++;
}
int core=;
for (i=;i<=n;i++)
{
if (deg[i]==)core=i;
if (!core && deg[i]%==)core=i;
}
if (!core)core=;
dfs(core,core);
}
set<pair<int,int> > S;
int main()
{
//freopen(PROB".in","r",stdin);
//freopen(PROB".out","w",stdout);
int l;
scanf("%d%d",&n,&l);
int i,j,k;
int x,y,z;
for (i=;i<l;i++)
{
scanf("%d",&x);
scanf("%d",&y);
for (j=;j<x;j++)
{
scanf("%d",&z);
e[m].x=y;
e[m].y=z;
m++;
y=z;
}
}
for (i=;i<m;i++)
{
if (e[i].x>e[i].y)swap(e[i].x,e[i].y);
if (e[i].x==e[i].y || S.find(make_pair(e[i].x,e[i].y))!=S.end())
{
i--;m--;
continue;
}else
{
S.insert(make_pair(e[i].x,e[i].y));
}
e[i].id=i;
}
work();
printf("%d\n",ans);
}

bzoj 1023: [SHOI2008]cactus仙人掌图 tarjan缩环&&环上单调队列的更多相关文章

  1. bzoj 1023: [SHOI2008]cactus仙人掌图【tarjan+dp+单调队列】

    本来想先求出点双再一个一个处理结果写了很长发现太麻烦 设f[u]为u点向下的最长链 就是再tarjan的过程中,先照常处理,用最长儿子链和次长儿子链更新按ans,然后处理以这个点为根的环,也就是这个点 ...

  2. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图

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

  3. BZOJ.1023.[SHOI2008]cactus仙人掌图(DP)

    题目链接 类似求树的直径,可以用(类似)树形DP求每个点其子树(在仙人掌上就是诱导子图)最长链.次长链,用每个点子节点不同子树的 max{最长链}+max{次长链} 更新答案.(不需要存次长链,求解过 ...

  4. bzoj 1023: [SHOI2008]cactus仙人掌图 2125: 最短路 4728: 挪威的森林 静态仙人掌上路径长度的维护系列

    %%% http://immortalco.blog.uoj.ac/blog/1955 一个通用的写法是建树,对每个环建一个新点,去掉环上的边,原先环上每个点到新点连边,边权为点到环根的最短/长路长度 ...

  5. bzoj 1023: [SHOI2008]cactus仙人掌图

    这道题是我做的第一道仙人掌DP,小小纪念一下…… 仙人掌DP就是环上的点环状DP,树上的点树上DP.就是说,做一遍DFS,DFS的过程中处理出环,环上的点先不DP,先把这些换上的点的后继点都处理出来, ...

  6. BZOJ 1023: [SHOI2008]cactus仙人掌图 | 在仙人掌上跑DP

    题目: 求仙人掌直径 http://www.lydsy.com/JudgeOnline/problem.php?id=1023 题解: 首先给出仙人掌的定义:满足所有的边至多在一个环上的无向联通图 我 ...

  7. bzoj 1023 [SHOI2008]cactus仙人掌图 ( poj 3567 Cactus Reloaded )——仙人掌直径模板

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1023 http://poj.org/problem?id=3567 因为lyd在讲课,所以有 ...

  8. 1023: [SHOI2008]cactus仙人掌图 - BZOJ

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

  9. 【BZOJ】1023: [SHOI2008]cactus仙人掌图 静态仙人掌(DFS树)

    [题意]给定仙人掌图(每条边至多在一个简单环上),求直径(最长的点对最短路径).n<=50000,m<=10^7. [算法]DFS树处理仙人掌 [题解]参考:仙人掌相关问题的处理方法(未完 ...

随机推荐

  1. 简单的实现QQ通信功能(二)

    第二部分:功能需求以及大体思路 一:功能需求: 1. 角色:登录用户. 2. 登录: (1)检查用户名和密码是否正确,正确登录成功,否则提醒用户名或密码错误. (2)登录时可以选择登录状态,送入数据库 ...

  2. angular下H5上传图片(可多张上传)

    最近做的项目中用到了angular下上传图片功能,在做的过程中遇到了许多问题,最终都得以解决 angular上传时和普通上传时过程差不多,只不过是要不一些东西转化为angular的东西. 1.ng-f ...

  3. 怎么用js代码改变单选框的选中状态

    今天突然有一个需求要用到,使用js代码改变单选框的选中状态.当时想也不想直接 function doGender(gender) { if (gender == "男") { ge ...

  4. 【C#】获取本地Cookie的问题

    using System; using System.Net; using System.IO; using System.Text; // // TODO: 在此处添加代码以启动应用程序 // st ...

  5. 球面墨卡托(Spherical Mercator)

    地理信息描述空间位置相关的信息,在空间位置的表达中,需要基于空间参照系来保证数据精度以及不同数据源之间的相互叠加/空间分析操作.自Google Maps与2005年发布以来,电子地图服务与普通民众的日 ...

  6. WPF:保存窗口当前状态截图方法

    在制作软件使用手册或者操作示范市,比较常用方式有截图和视频制作.如果软件内置当前状态的截图和操作视频的导出功能,则将极大简化这方面的工作.使用wpf编写的UI界面,截图的导出功能逻辑相对简单,通用的实 ...

  7. OC加强-day05

    #program mark - 0_11 NSRange结构体介绍 [掌握] 是Foundation框架中的一个结构体 NSRange 定义的一个变量的两个属性 location:起始下标 lengt ...

  8. weewwe

    http://blog.csdn.net/u013073524/article/details/25912891

  9. Cesium的api之关于viewer(二)

    1.构建一个viewer,如下创建:options的参数根据实际情况,进行设定 var viewer = new Cesium.Viewer('cesiumContainer', { //Start ...

  10. 根据id设置、获取元素的文本和value

    /** * 根据id获取元素文本 * @param {String} id|元素id * return {Integer || String} text */function getText(id){ ...