Codeforces 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的更多相关文章
- Cactus CodeForces - 231E (无向图缩环)
大意: 给定无向图, 每个点最多属于一个简单环, 多组询问, 求给定起点终点, 有多少条简单路径. 先缩环, 然后假设两点树上路径经过$cnt$个环, 那么答案就为$2^{cnt}$. 要注意缩环建树 ...
- Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列
原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...
- 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 ...
- Codeforces 1236F - Alice and the Cactus(期望+分类讨论)
Codeforces 题面传送门 & 洛谷题面传送门 期望好题. 首先拆方差: \[\begin{aligned} &E((x-E(x))^2)\\ =&E(x^2)-2E(x ...
- Codeforces 856D - Masha and Cactus(树链剖分优化 dp)
题面传送门 题意: 给你一棵 \(n\) 个顶点的树和 \(m\) 条带权值的附加边 你要选择一些附加边加入原树中使其成为一个仙人掌(每个点最多属于 \(1\) 个简单环) 求你选择的附加边权值之和的 ...
- [Codeforces]856D - Masha and Cactus
题目大意:给出一棵树和若干条可以加入的边,要求加入若干条边使图是仙人掌并且加入的边权和最大,仙人掌定义为没有一个点属于超过1个环.(n,m<=200,000) 做法:这题的仙人掌跟平时见到的不太 ...
- python爬虫学习(5) —— 扒一下codeforces题面
上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...
- 【Codeforces 738D】Sea Battle(贪心)
http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...
- 【Codeforces 738C】Road to Cinema
http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...
随机推荐
- 你一定要知道的关于Linux文件目录操作的12个常用命令
写在前面: 1,<你一定要知道的关于Linux文件目录操作的12个常用命令>是楼主收集的关于Linux文件目录操作最常用的命令,包括文件或目录的新建.拷贝.移动.删除.查看等,是开发人员操 ...
- 完全卸载mysql 停止服务、卸载相关程序、删除注册表
本节主要介绍了完全卸载mysql的具体步骤包括停止服务.卸载相关程序.删除注册表等等 1. 停止服务MySQL 2. 卸载mysql相关的程序 3. 删除注册表(运行->regedit),m ...
- 【POJ1082】Calendar Game (博弈)
[题目] Description Adam and Eve enter this year's ACM International Collegiate Programming Contest. La ...
- View的getLeft, getRight, getTop, getBottom
View的getLeft, getRight, getTop, getBottom方法得到的分别是相对于其父组件原点坐标不同方向的距离 网上找了张图说明: 其中right和left的计算方法如下: r ...
- Java 比较两个字符串的大小
比较两个字符串的大小 static int compareTo(String s1, String s2) { int len1 = s1.length(); int len2 = s2.length ...
- linux No manual entry for
我的博客:www.while0.com 原来除了安装man,还要安装man-pages. yum install man -y yum install man-pages -y
- 14.5.5.3 How to Minimize and Handle Deadlocks 如何减少和处理死锁
14.5.5.3 How to Minimize and Handle Deadlocks 如何减少和处理死锁 这个部分建立在概念信息关于deadlocks 在章节 14.5.5.2, "D ...
- Node.js权威指南 (9) - 进程与子进程
9.1 Node.js中的进程 / 225 9.1.1 进程对象的属性 / 225 9.1.2 进程对象的方法与事件 / 2279.2 创建多进程应用程序 / 235 9.2.1 使用spawn方法开 ...
- WebSorcket学习
传统 Web 模式在处理高并发及实时性需求的时候经常采用以下方案: 1.轮询,原理简单易懂,就是客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步.问题很明显, ...
- JavaScript高级程序设计10.pdf
String类型有几种操作字符串的方法 concat()方法拼接任意多个字符串,不修改原字符串 var stringValue=“hello ”; var result=stringValue.con ...