题目描述

仙人掌图(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。注意最后的答案可能是一个很大很大的数。

输入输出样例

输入 #1复制

14 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
2 2 14
输出 #1复制

35
输入 #2复制

10 2
7 1 2 3 4 5 6 1
6 3 7 8 9 10 2
输出 #2复制

0
输入 #3复制

5 1
4 1 2 3 4
输出 #3复制

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]仙人掌的更多相关文章

  1. 2018.10.29 洛谷P4129 [SHOI2006]仙人掌(仙人掌+高精度)

    传送门 显然求出每一个环的大小. Ans=∏i(siz[i]+1)Ans=\prod_i(siz[i]+1)Ans=∏i​(siz[i]+1) 注意用高精度存答案. 代码: #include<b ...

  2. Luogu 4244 [SHOI2008]仙人掌图

    BZOJ 1023 如果我们把所有的环都缩成一个点,那么整张图就变成了一棵树,我们可以直接$dp$算出树的直径. 设$f_x$表示$x$的子树中最长链的长度,那么对于$x$的每一个儿子$y$,先用$f ...

  3. pkuwc 前的任务计划

    菜鸡 wxw 的计划(肯定会咕咕咕 12.27 luogu P4244 [SHOI2008]仙人掌图 II(咕咕咕 luogu P4246 [SHOI2008]堵塞的交通 (没有咕! luogu P1 ...

  4. luogu P3180 [HAOI2016]地图 仙人掌 线段树合并 圆方树

    LINK:地图 考虑如果是一棵树怎么做 权值可以离散 那么可以直接利用dsu on tree+树状数组解决. 当然 也可以使用莫队 不过前缀和比较难以维护 外面套个树状数组又带了个log 套分块然后就 ...

  5. luogu 2478 [SDOI2010]城市规划 仙人掌上dp.

    LINK:城市规划 以前ls 让写的时候由于看不懂题目+以为在图中的环上dp非常困难所以放弃治疗了. 现在终于能把题目看懂了 泪目... 题目其实就是在说 给出一张图这个有一个非常好的性质 满足每个点 ...

  6. ●洛谷P3687 [ZJOI2017]仙人掌

    题链: https://www.luogu.org/problemnew/show/P3687题解: 计数DP,树形DP. (首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0) 然后由于本来 ...

  7. 图论杂项细节梳理&模板(虚树,圆方树,仙人掌,欧拉路径,还有。。。)

    orzYCB 虚树 %自为风月马前卒巨佬% 用于优化一类树形DP问题. 当状态转移只和树中的某些关键点有关的时候,我们把这些点和它们两两之间的LCA弄出来,以点的祖孙关系连成一棵新的树,这就是虚树. ...

  8. LOJ #2547 Luogu P4517「JSOI2018」防御网络

    好像也没那么难写 LOJ #2547 Luogu P4517 题意 在一棵点仙人掌中等概率选择一个点集 求选出点集的斯坦纳树大小的期望 定义点仙人掌为不存在一个点在多个简单环中的连通图 斯坦纳树为在原 ...

  9. 仙人掌&圆方树

    仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...

随机推荐

  1. 【JQuery 选择器】 案例

    1.查找以id的某个字段开头的元素 setTimeout(function () { $("a[id^='menu_']").each(function () { $(this). ...

  2. java中关于&0xFF 的问题

    最近遇到一个问题,半天也没想明白,byte temp = 0xA0,为什么System.out.println(temp),打印的值为:-96:而System.out.println(temp& ...

  3. nodejs的forEach不支持break打断

  4. 一个简单的PHP文件下载方法 download

    <?php /* * *@param function downloadFile 文件下载 * *@param string $filename 下载文件的路径(根目录下的绝对路径) * *@p ...

  5. Java中的基本数据类型语法补充

    变量要先赋值后使用 不给变量赋值代表什么 不赋值就使用会怎样 (会报错) 计算并赋值运算符 作用是为了让代码更加简洁.比如 a = a + 10,可以简化为 a+=10 += -= *= /= %= ...

  6. 在iOS项目中,这样才能完美的修改项目名称

    https://www.cnblogs.com/liangyi-cn/p/8657474.html 前言: 在iOS开发中,有时候想改一下项目的名字,这会遇到很多麻烦. 直接改项目名的话,Xcode不 ...

  7. Java基础知识笔记第七章:内部类和异常类

    内部类 /* *Java支持在一个类中定义另一个类,这样的类称为内部类,而包含内部类的类称为内部类的外嵌类 */ 重要关系: /* *1.内部类的外嵌类在内部类中仍然有效,内部类的方法也可以外嵌类的方 ...

  8. IELTS Writing Task 2: 'music' essay

    IELTS Writing Task 2: 'music' essay Here's my band 9 sample answer for the question below. Some peop ...

  9. 第1节 Scala基础语法:scala中的方法源码分析

    val list=List(1,2,3,4) list.reduce((x:Int,y:Int)=>x+y)--->list.reduceLeft((x:Int,y:Int)=>x+ ...

  10. SELinux永久关闭

    目录 SELinux永久关闭 参考 SELinux三种模式 永久关闭方法 SELinux永久关闭