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 1
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

Sample Output 1
8

Sample Input 2
10 1
10 1 2 3 4 5 6 7 8 9 10

Sample Output 2
9

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

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


首先建立一棵圆方树,记每个环上dfs序最小的点为\(x_i\),则每个环代表的方点向各自所拥有的\(x_i\)连一条边权为1的边,环上其他的圆点向方点连一条边权为圆点到所属\(x_i\)最短距离的边

然后我们求圆方树的直径,显然是需要记录一条最长链\((f[i])\)和次长链\((g[i])\)的。如果当前点是圆点,则直接用\(f[i]+g[i]\)更新答案;如果当前点是方点,则考虑环上所有点(除去每个环内的\(x_i\),因为在圆方树上\(x_i\)是方点的父亲),按照一定顺序,用单调队列维护\(f[i]+f[j]+dis(i,j)\)的最大值即可

单调队列那里显然要破环成链然后倍长……但是我发现我没有倍长也过了……

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){int x=0,f=1; char ch=gc();for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';return x*f;
}
inline int read(){int x=0,f=1; char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';return x*f;
}
inline void print(int x){if (x<0)    putchar('-'),x=-x;if (x>9)    print(x/10);putchar(x%10+'0');
}
const int N=1e5,M=2e5;
int V[N+10],deep[N+10],dfn[N+10],belong[N+10];
int n,m,Ans,cnt;
vector<int>vec[N+10];
int dis(int x,int y,int pos){if (!x||!y) return 0;if (dfn[x]<dfn[y])  swap(x,y);return min(deep[x]-deep[y],V[pos]-deep[x]+deep[y]);
}
struct S1{int pre[(M<<1)+10],now[M+10],child[(M<<1)+10],val[(M<<1)+10],tot;int f[M+10],g[M+10],fa[M+10];void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}int work(int pos){static int h[(N<<1)+10];int head=1,tail=0,res=0; h[1]=0;//记得清空h[1]for (vector<int>::iterator it=vec[pos].begin();it!=vec[pos].end();it++){if (it==vec[pos].begin())   continue;while (head<=tail&&(dis(h[head],*it,pos)>V[pos]/2||h[head]==*it))   head++;res=max(res,f[*it]+f[h[head]]+dis(h[head],*it,pos));while (head<=tail&&f[h[tail]]<=f[*it])  tail--;h[++tail]=*it;}for (vector<int>::iterator it=vec[pos].begin();it!=vec[pos].end();it++){if (it==vec[pos].begin())   continue;while (head<=tail&&(dis(h[head],*it,pos)>V[pos]/2||h[head]==*it))   head++;res=max(res,f[*it]+f[h[head]]+dis(h[head],*it,pos));while (head<=tail&&f[h[tail]]<=f[*it])  tail--;h[++tail]=*it;}return res;}void dfs(int x){for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;fa[son]=x,dfs(son);int V=f[son]+val[p];if (f[x]<V) g[x]=f[x],f[x]=V;else    if (g[x]<V) g[x]=V;}if (x<=n)   Ans=max(Ans,f[x]+g[x]);else    Ans=max(Ans,work(x-n));}
}RST;//Round Square Tree
struct S2{int pre[(M<<1)+10],now[N+10],child[(M<<1)+10];int fa[N+10],stack[N+10],low[N+10];int Time,tot,top,num;bool instack[N+10];void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}void insert(int x,int y){join(x,y),join(y,x);}void dfs(int x){dfn[x]=++Time,deep[x]=deep[fa[x]]+1;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;if (!dfn[son]){fa[son]=x;dfs(son);}else   if (dfn[son]<dfn[x]){V[++cnt]=deep[x]-deep[son]+1;vec[cnt].push_back(son),RST.insert(cnt+n,son,0);for (int i=x;i!=son;i=fa[i])    vec[cnt].push_back(i),RST.insert(cnt+n,i,dis(i,son,cnt));}}}void tarjan(int x){dfn[x]=low[x]=++Time;instack[stack[++top]=x]=1;for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){if (son==fa[x]) continue;if (!dfn[son])  tarjan(son),low[x]=min(low[x],low[son]);else    if (instack[son])   low[x]=min(low[x],dfn[son]);}if (low[x]==dfn[x]){instack[x]=0,belong[x]=++num;while (stack[top]!=x)   instack[stack[top]]=0,belong[stack[top--]]=num;top--;}}void init(){Time=0;memset(dfn,0,sizeof(dfn));}
}OT;//Original Tree
struct S3{int x,y;void insert(int _x,int _y){x=_x,y=_y;}
}Line[M+10];
int main(){n=read(),m=read();int L_cnt=0;for (int i=1;i<=m;i++){int k=read(),last=read();for (int j=1;j<k;j++){int x=read();OT.insert(last,x);Line[++L_cnt].insert(last,x);last=x;}}OT.dfs(1),OT.init(),OT.tarjan(1);for (int i=1;i<=L_cnt;i++)if (belong[Line[i].x]!=belong[Line[i].y])RST.insert(Line[i].x,Line[i].y,1);RST.dfs(1);printf("%d\n",Ans);return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10284295.html

[SHOI2008]cactus仙人掌图相关推荐

  1. bzoj 1023: [SHOI2008]cactus仙人掌图(仙人掌求直径)

    1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 3668  Solved: 1535 [Submi ...

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

    1023: [SHOI2008]cactus仙人掌图 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2907  Solved: 1212 [Submi ...

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

    Time Limit: 1 Sec  Memory Limit: 162 MB Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这 ...

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

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

  5. BZOJ1023[SHOI2008]cactus仙人掌图 【仙人掌DP】

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

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

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

  7. [bzoj1023][SHOI2008]cactus仙人掌图【仙人掌】

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1023 [题解] 仙人掌入门题,拿圆方树练练手. 圆方树就是把一个环建一个新方点,然后向 ...

  8. 2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌图(仙人掌+单调队列优化dp)

    传送门 求仙人掌的直径. 感觉不是很难. 分点在环上面和不在环上分类讨论. 不在环上直接树形dpdpdp. 然后如果在环上讨论一波. 首先对环的祖先有贡献的只有环上dfsdfsdfs序最小的点. 对答 ...

  9. BZOJ1023 [SHOI2008]cactus仙人掌图

    滚回第一页去了... 好吧,看了题解蒟蒻也写不粗来,怎么办捏? 看这个吧:Orz YDC巨巨:但是巨巨写的程序又不优美,于是程序Orz hzwer 其实这题的重点在于tarjan和单调队列dp里&qu ...

最新文章

  1. Android studio git 本地仓库和远程仓库节点对比
  2. 一个通用数据库操作组件DBUtil(c#)、支持SqlServer、Oracle、Mysql、postgres、SQLITE
  3. Windows下安装scikit-learn
  4. 我的第一本算法书(图解算法)——什么是二叉查找树
  5. 安卓平板python编程软件下载_10 个可以在平板电脑上使用的 Python 编辑器
  6. 蓝牙5最大速率分析报告
  7. 《聪明人用方格笔记本》读书笔记
  8. LeetCode1359. 有效的快递序列数目
  9. 基于Arduino的智能泡茶机(1)——机械系机械创新比赛总结技术点与不足处
  10. 【云原生】这么火,你不来了解下?
  11. 英语Canutillos祖母绿canutillos单词
  12. 多线程相关知识点总结
  13. 吉林大学计算机学院考研大纲,吉林大学计算机科学与技术学院2020考研复试大纲预测...
  14. C++内存写越界导致堆内存被破坏致使new失败的问题定位总结
  15. win10平板续航测试软件,Win10平板最低配置:续航最低8小时
  16. 网线排序 掐网线的顺序
  17. 最新QT从入门到实战完整版(08.qt中的坐标系-09 信号和槽-点击按钮关闭窗口_)
  18. [今日记录]EFCore跟踪与非跟踪查询 AsNoTracking()
  19. 毕业一年月薪50K,他的竞争力在哪里?
  20. idea搭建spark开发环境完整版(windows)

热门文章

  1. python中如何调用或修改元组中的元素_python 元组的使用方法
  2. 【WebRTC---源码篇】(四)WebRTC线程模型
  3. 【WebRTC---进阶篇】(二)libevent实现高性能网络服务器
  4. diveintopython3 official_Python 学习资料整理
  5. C语言“fread”函数的用法?
  6. C语言中sizeof和strlen的区别是什么
  7. html中引入js柱状图,Echarts.js 图表在layui中的引用
  8. php如何解释xml,PHP – 如何解析这个xml?
  9. python高手之路第三版_《Python高手之路(第3版)》——1.3 版本编号-阿里云开发者社区...
  10. python输入input数组_python怎么输入数组