231E - Cactus

给一个10^5个点的无向图,每个点最多属于一个环,规定两点之间的简单路:从起点到终点,经过的边不重复

给10^5个询问,每个询问两个点,问这两个点之间有多少条简单路。

挺综合的一道题目,无向图连通分量,缩点,LCA 都考察到了。。

因为每个点最多属于一个环,因此把所有环缩点,就可以得到一棵树

然后对于每个询问,用LCA查找从起点到终点有多少个环

并查集处理的时候挂了一发,注意LCA时合并两个并查集,根节点深度小的作为父亲。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<string>
#include<sstream>
#define eps 1e-9
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define MAXN 100005
#define MAXM 400005
#define INF 0x3fffffff
#define PB push_back
#define MP make_pair
#define X first
#define Y second
#define clr(x,y) memset(x,y,sizeof(x));
using namespace std;
typedef long long LL;
int i,j,k,n,m,x,y,T,big,cas,len;
bool flag; int edge,head[MAXN],bin[MAXN],headS[MAXN],edgeS,vis[MAXN],d[MAXN],id[MAXN],num[MAXN];
struct edgenode
{
int to,next,flag;
} G[MAXM],S[MAXM]; void add_edge(int x,int y)
{
G[edge].to=y;
G[edge].flag=;
G[edge].next=head[x];
head[x]=edge++;
} void add_edgeS(int x,int y)
{
S[edgeS].to=y;
S[edgeS].flag=;
S[edgeS].next=headS[x];
headS[x]=edgeS++;
} int fa[MAXN];
int findset(int x)
{
return x==fa[x]?x:fa[x]=findset(fa[x]);
}
void unionset(int x,int y)
{
fa[findset(x)]=findset(y);
} int dfn[MAXN],low[MAXN],time;
void dfs(int u,int fa)
{
vis[u]=;
dfn[u]=low[u]=++time;
for (int i=head[u];i!=-;i=G[i].next)
{
int v=G[i].to;
if (v!=fa && vis[v]==)
{
low[u]=min(low[u],dfn[v]);
} if (!vis[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if (low[v]>dfn[u]) G[i].flag=;
}
}
vis[u]=;
} void dive(int u,int scc)
{
id[u]=scc;
vis[u]=;
num[scc]++;
for (int i=head[u];i!=-;i=G[i].next)
{
if (!G[i].flag && !vis[G[i].to])
dive(G[i].to,scc);
}
} void dis(int u,int dep)//记录当前节点到根节点有多少个“环”
{
vis[u]=;
d[u]=dep;
for (int i=headS[u];i!=-;i=S[i].next)
{
int v=S[i].to;
if (!vis[v])
{
if (num[v]>) dis(v,dep+);
else dis(v,dep);
}
}
} vector<pair<int,int> > Q[MAXN];
int ans[MAXN];
void tarjan(int u)
{
vis[u]=true;
for (int i=;i<Q[u].size();i++)
{
int v=Q[u][i].X,id=Q[u][i].Y;
if (vis[v])
{
int com=findset(v);
ans[id]=d[u]+d[v]-*d[com];
if (num[com]>) ans[id]++;
}
} for (int i=headS[u];i!=-;i=S[i].next)
{
int v=S[i].to;
if (!vis[v])
{
tarjan(v);
unionset(v,u);
}
}
} int main()
{
memset(head,-,sizeof(head));
edge=;
memset(headS,-,sizeof(headS));
edgeS=;
scanf("%d%d",&n,&m);
while (m--)
{
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
} dfs(,-); memset(vis,,sizeof(vis));
int scc=;
for (int i=;i<=n;i++)
{
if (!vis[i]) dive(i,scc++);
} for (i=;i<=n;i++)
{
for (int j=head[i];j!=-;j=G[j].next)
{
int v=G[j].to;
if (id[i]!=id[v])
{
add_edgeS(id[i],id[v]);
add_edgeS(id[v],id[i]);
}
}
} int q;
scanf("%d",&q);
for (i=;i<q;i++)
{
scanf("%d%d",&x,&y);
x=id[x];y=id[y];
Q[x].PB(MP(y,i));
Q[y].PB(MP(x,i));
} memset(vis,,sizeof(vis));
if (num[]>) dis(,); else dis(,); memset(vis,,sizeof(vis));
for (i=;i<=n;i++) fa[i]=i;
tarjan(); bin[]=;
for(int i=;i<MAXN;i++)
bin[i]=bin[i-]*%;
for (int i=;i<q;i++)
{
printf("%d\n",bin[ans[i]]);
}
return ;
}

Codeforces 231E - Cactus的更多相关文章

  1. Cactus CodeForces - 231E (无向图缩环)

    大意: 给定无向图, 每个点最多属于一个简单环, 多组询问, 求给定起点终点, 有多少条简单路径. 先缩环, 然后假设两点树上路径经过$cnt$个环, 那么答案就为$2^{cnt}$. 要注意缩环建树 ...

  2. Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...

  3. Codeforces Round #143 (Div. 2) E. Cactus 无向图缩环+LCA

    E. Cactus   A connected undirected graph is called a vertex cactus, if each vertex of this graph bel ...

  4. Codeforces 1236F - Alice and the Cactus(期望+分类讨论)

    Codeforces 题面传送门 & 洛谷题面传送门 期望好题. 首先拆方差: \[\begin{aligned} &E((x-E(x))^2)\\ =&E(x^2)-2E(x ...

  5. Codeforces 856D - Masha and Cactus(树链剖分优化 dp)

    题面传送门 题意: 给你一棵 \(n\) 个顶点的树和 \(m\) 条带权值的附加边 你要选择一些附加边加入原树中使其成为一个仙人掌(每个点最多属于 \(1\) 个简单环) 求你选择的附加边权值之和的 ...

  6. [Codeforces]856D - Masha and Cactus

    题目大意:给出一棵树和若干条可以加入的边,要求加入若干条边使图是仙人掌并且加入的边权和最大,仙人掌定义为没有一个点属于超过1个环.(n,m<=200,000) 做法:这题的仙人掌跟平时见到的不太 ...

  7. python爬虫学习(5) —— 扒一下codeforces题面

    上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...

  8. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  9. 【Codeforces 738C】Road to Cinema

    http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...

随机推荐

  1. JS模块加载器加载原理是怎么样的?

    路人一: 原理一:id即路径 原则.通常我们的入口是这样的: require( [ 'a', 'b' ], callback ) .这里的 'a'.'b' 都是 ModuleId.通过 id 和路径的 ...

  2. Angular 2 npm start 报错

    首先, index.html 和styles.css是和app目录平级的, 不要扔到里面去, 否则会404 确认配置文件齐全, 路径都正确之后 npm start What?! 照着快速起步也会弄错吗 ...

  3. FLASH 存储学习-串行SPI NOR FLASH

    1.1 SST25VF080B简介1.1.1 主要特性 关键点:容量.速度(时钟速度.读写速度).功耗. l 容量:8MBit: l 最高SPI时钟频率:50MHz: l 低功耗模式下电流消耗:5uA ...

  4. 几个外国Delphi Blog网站

    http://blog.blong.com/search?updated-max=2012-09-19T03:21:00-07:00&max-results=7&start=42&am ...

  5. Remove highlight from document(Aspose Word 删除高亮)

    Thanks for your inquiry. You can do it using DocumentVisitor. Please try using the following code: / ...

  6. Git命令详解

    一个中文git手册:http://progit.org/book/zh/ 原文:http://blog.csdn.net/sunboy_2050/article/details/7529841 前面两 ...

  7. mysql 累加排序求名次

    自己做的一个小项目里需要用mysql计算一些信息. mysql中的 表如下(注:表中数据都是测试数据,随机生成的) mysql> select * from shake_log; +-----+ ...

  8. Linux驱动的两种加载方式过程分析

    一.概念简述 在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载. 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用.静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新 ...

  9. unity3d shader之God Ray上帝之光

    又是一个post-process后期效果,god ray 上帝之光,说起上帝之光就是咱们再看太阳时太阳周围一圈的针状光芒先放组效果,本文的场景资源均来自浅墨大神,效果为本文shader效果 加入了前篇 ...

  10. 定时器NSTimer的用法

        //时间间隔     NSTimeInterval activeTimeInterval = NETWORK_SEND_ACTIVE_TIME;     NSTimeInterval othe ...