luogu P4129 [SHOI2006]仙人掌
题目描述
仙人掌图(cactus)是一种无向连通图,它的每条边最多只能出现在一个简单回路(simple cycle)里面。从直观上说,可以把仙人掌图理解为允许存在回路的树。但是仙人掌图和树之间有个本质的不同,仙人掌图可以拥有多个支撑子图(spanning subgraph),而树的支撑子图只有一个(它自身),我们把仙人掌图的支撑子图的数目称为“仙人数”。你的任务就是计算给定图的“仙人数”。
一些关于仙人掌图的举例:
第一张图是一个仙人掌图,第二张图的边(2,3)在两个不同的回路里面,所以不是仙人掌图,第三张图不是一个连通图,所以也不是仙人掌图。
以下是对一些术语的解释:
简单回路(simple cycle):简单回路是原图的一条路径,这条路径的边集构成了回路,回路中顶点只能出现一次。比如对于上例中第二个图来说,它一共有三个简单回路,分别是(4,3,2,1,6,5)、(7,8,9,10,2,3)和(4,3,7,8,9,10,2,1,6,5)
支撑子图(spanning subgraph):支撑子图也是原图的子图,这种子图可以比原来少一些边,但是不能破坏图的连通性,也不能去除原来图上的任何顶点。“支撑”的概念类似于我们熟知的“最小支撑树”,对于上例中的第一张图来说,任意去除回路I中的图或回路II中的一条边都能构成一个支撑子图,所以它的支撑子图一共有6 + 4 + 6 × 4 + 1 = 35种(注意图自身也是自己的一个子图)
输入格式
输入文件的第一行是两个整数n和m(1≤n≤20000, 0≤m≤1000)。n代表图的顶点数,顶点的编号总是从1到n表示的。
接下来一共有m行。每行都代表了图上的一条路径(注意:这里所表示的一条路径可不一定是一条回路)。这些行的格式是首先有一个整数ki(2≤ki≤1000)代表这条路径通过了几个顶点,接下来是ki个在1到n之间的数字,其中每个数字代表了图上的一个顶点,相邻的顶点之间就定义了一条边。一条路径上可能通过一个顶点好几次,比如对于第一个例子,第一条路径从2经过3,又从8返回到了3,但是我们保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。
输出格式
输出这张图的“仙人数”,如果它不是一张仙人掌图,输出0。注意最后的答案可能是一个很大很大的数。
输入输出样例
14 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
2 2 14
35
10 2
7 1 2 3 4 5 6 1
6 3 7 8 9 10 2
0
5 1
4 1 2 3 4
0 思路:注意高精度和与点双不同的是判简单环边数即可
typedef long long LL;
typedef pair<LL, LL> PLL;
const LL bas = ; struct Big_Number {
LL a[],len;
void init() {
len = ;
memset(a, , sizeof a);
a[] = ;
}
void mul(LL val) {
for (int i = ; i < len; i++) {
a[i] = a[i] * val;
}
for (int i = ; i < len; i++){
a[i + ] += a[i] / bas;
a[i] %= bas;
}
while (a[len]) {
a[len + ] = a[len] / bas;
a[len] %= bas;
len++;
}
}
void print() {
printf("%lld", a[len - ]);
for (int i = len - ; i >= ; i--) {
printf("%.8lld", a[i]);
}
printf("\n");
}
} ans; const int maxm = 2e6+;
const int maxn = 2e5+; int head[maxm], edgecnt, dfn[maxn], low[maxn], bcc_cnt, bccnum[maxn], dfs_clock, s[maxm], top, vis[maxn], num;
LL bcc[maxn];
bool ok = true; struct edge{
int u, v, nex;
} edges[maxm]; void addedge(int u, int v) {
edges[++edgecnt].u = u;
edges[edgecnt].v = v;
edges[edgecnt].nex = head[u];
head[u] = edgecnt;
} void dfs(int u, int fa) {
vis[u] = ;
++num;
for(int i = head[u]; i; i = edges[i].nex) {
int v = edges[i].v;
if(v == fa) continue;
if(!vis[v])
dfs(v, u);
}
} void tarjan(int u, int fa) {
dfn[u] = low[u] = ++dfs_clock;
int child = , v;
for(int i = head[u]; i; i = edges[i].nex) {
v = edges[i].v;
if(v == fa) continue;
if(!dfn[v]) {
s[++top] = i;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
++bcc_cnt;
LL vet = ;
while(true) {
int num = s[top--];
if(bccnum[edges[num].v] != bcc_cnt) {
vet++;
bccnum[edges[num].v]=bcc_cnt;
} else ok = false;
if(edges[num].u == u && edges[num].v == v) break;
}
if(ok && vet>)
ans.mul(vet+);
}
} else if(dfn[v] < dfn[u]){
s[++top] = i;
low[u] = min(low[u], dfn[v]);
}
}
} void run_case() {
int n, m, u, v, t;
ans.init();
cin >> n >> m;
for(int i = ; i <= m; ++i) {
cin >> t;
t--;
cin >> u;
while(t--) {
cin >> v;
addedge(u, v), addedge(v, u);
u = v;
}
}
dfs(n, -);
if(n != num) {
cout << "";
return;
}
tarjan(, -);
if(!ok) cout << "";
else
ans.print();
} int main() {
//ios::sync_with_stdio(false), cin.tie(0);
run_case();
return ;
}
(自用板,记录每一个点双和割点
luogu P4129 [SHOI2006]仙人掌的更多相关文章
- 2018.10.29 洛谷P4129 [SHOI2006]仙人掌(仙人掌+高精度)
传送门 显然求出每一个环的大小. Ans=∏i(siz[i]+1)Ans=\prod_i(siz[i]+1)Ans=∏i(siz[i]+1) 注意用高精度存答案. 代码: #include<b ...
- Luogu 4244 [SHOI2008]仙人掌图
BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...
- pkuwc 前的任务计划
菜鸡 wxw 的计划(肯定会咕咕咕 12.27 luogu P4244 [SHOI2008]仙人掌图 II(咕咕咕 luogu P4246 [SHOI2008]堵塞的交通 (没有咕! luogu P1 ...
- luogu P3180 [HAOI2016]地图 仙人掌 线段树合并 圆方树
LINK:地图 考虑如果是一棵树怎么做 权值可以离散 那么可以直接利用dsu on tree+树状数组解决. 当然 也可以使用莫队 不过前缀和比较难以维护 外面套个树状数组又带了个log 套分块然后就 ...
- luogu 2478 [SDOI2010]城市规划 仙人掌上dp.
LINK:城市规划 以前ls 让写的时候由于看不懂题目+以为在图中的环上dp非常困难所以放弃治疗了. 现在终于能把题目看懂了 泪目... 题目其实就是在说 给出一张图这个有一个非常好的性质 满足每个点 ...
- ●洛谷P3687 [ZJOI2017]仙人掌
题链: https://www.luogu.org/problemnew/show/P3687题解: 计数DP,树形DP. (首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0) 然后由于本来 ...
- 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)
orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...
- LOJ #2547 Luogu P4517「JSOI2018」防御网络
好像也没那么难写 LOJ #2547 Luogu P4517 题意 在一棵点仙人掌中等概率选择一个点集 求选出点集的斯坦纳树大小的期望 定义点仙人掌为不存在一个点在多个简单环中的连通图 斯坦纳树为在原 ...
- 仙人掌&圆方树
仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...
随机推荐
- 免费https/ssl通配证书(letsencrypt)安装
教程:免费https/ssl通配证书(letsencrypt)安装 前置条件 开发443端口 关闭nginx .获取脚本 wget https://dl.eff.org/certbot-auto .执 ...
- BUG搬运工:CSCun88303-CIMC Memory Leak : Can't SSH/HTTP to CIMC
Symptom:Unable to SSH/HTTP to the CIMC of the C-series server, however the CIMC can be pinged. Also ...
- 19市赛 树状数组 第k个小的糖果
int find_kth(int k) { , cnt = , i; ; i >= ; i--)/ { ans += ( << i); if (ans >= maxn|| cn ...
- C语言-断言
1 作用: 断言常做语言处理的高级形式,自动处理软件隐藏很深其且它手段不易发现的错误,快速进行异常定位.同时这也是软件单元测试必须的技术. 2 使用范围: 2.1放在函数入口对入口参数进行合法性检查( ...
- Spring AOP 中 advice 的四种类型 before after throwing advice around
spring AOP(Aspect-oriented programming) 是用于切面编程,简单的来说:AOP相当于一个拦截器,去拦截一些处理,例如:当一个方法执行的时候,Spring 能够拦截 ...
- Nginx实现HTTP及TCP负载均衡
这种通过一台apache的服务器把客户请求分别传递给两台tomcat叫负载均衡 ========================================= ================= ...
- typeof方法重写(区分数组对象)
为什么要重写typeof方法? typeof 可以准确的判断除object以外的基础数据类型,但不能区分object类型的具体类型,比如 Array .Date.NULL.NaN 以及自定义类. 观察 ...
- 苹果应用商店AppStore审核规则指南
http://www.zesmob.com/blog/40161.html 新应用上架苹果AppStore或重大版本更新时,往往会被拒多次,造成审核不通过的原因,主要是因为对苹果应用商店AppStor ...
- php 随机生成汉字
function getChar($num) // $num为生成汉字的数量 { $b = ''; for ($i=0; $i<$num; $i++) { // 使用chr()函数拼接双字节汉字 ...
- POJ 2104 主席树模板题
#include <iostream> #include <cstdio> #include <algorithm> int const maxn = 200010 ...