标签:std 点双 树剖 int top wson dep while P2783
P2783 有机化学之神偶尔会做作弊
史上最水黑题
做法很暴力:tarjan算法求点双缩点,建新图,跑树剖或倍增,求LCA,通过深度算出答案即可。
点双的做法跟强连通分量的tarjan算法极其相似,唯一的一点不同就在于不能回到父节点。
要是回父节点的话那都有两个点大小的环咯
自己交上去45pts,原来是因为求LCA的时候下标弄错了。应该使用新图的下标。
代码:
/*************************************************************************
@Author: Garen
@Created Time : Thu 31 Jan 2019 05:21:10 PM CST
@File Name: P2783.cpp
@Description:
************************************************************************/
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
#define ll long long
const int maxn = 50005, maxm = 100005;
struct Edges {
int next, to;
} e[maxm << 1], e2[maxn << 1];
int head[maxn], tot;
int head2[maxn], tot2;
int n, m, q;
//
int dfn[maxn], low[maxn], dtot;
int stack[maxn << 1], stop;
bool vis[maxn];
int col[maxn], ctot;
//
int dep[maxn], fa[maxn], size[maxn], wson[maxn];
int top[maxn];
void link(int u, int v) {
e[++tot] = (Edges){head[u], v};
head[u] = tot;
}
void link2(int u, int v) {
e2[++tot2] = (Edges){head2[u], v};
head2[u] = tot2;
}
void tarjan(int u, int f) {
dfn[u] = low[u] = ++dtot;
stack[++stop] = u; vis[u] = true;
for(int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if(v == f) continue;
if(!dfn[v]) {
tarjan(v, u); low[u] = std::min(low[u], low[v]);
} else if(vis[v]) {
low[u] = std::min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]) {
ctot++;
int sb;
do {
sb = stack[stop--]; vis[sb] = false;
col[sb] = ctot;
} while(sb != u);
}
}
void dfs1(int u, int f) {
dep[u] = dep[f] + 1; fa[u] = f; size[u] = 1;
for(int i = head2[u]; i; i = e2[i].next) {
int v = e2[i].to;
if(v == fa[u]) continue;
dfs1(v, u);
size[u] += size[v];
if(size[v] > size[wson[u]]) wson[u] = v;
}
}
void dfs2(int u, int topf) {
top[u] = topf;
if(wson[u]) dfs2(wson[u], topf);
for(int i = head2[u]; i; i = e2[i].next) {
int v = e2[i].to;
if(v == wson[u] || v == fa[u]) continue;
dfs2(v, v);
}
}
int get_lca(int u, int v) {
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
u = fa[top[u]];
}
if(dep[u] > dep[v]) std::swap(u, v);
return u;
}
void print(int x) {
std::vector<int> buf;
while(x) {
buf.push_back(x & 1);
x >>= 1;
}
for(int i = buf.size() - 1; i >= 0; i--) cout << buf[i];
}
int main() {
cin >> n >> m;
while(m--) {
int u, v; cin >> u >> v;
link(u, v), link(v, u);
}
for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i, 0);
// print array col
//for(int i = 1; i <= n; i++) cout << col[i] << ' ';
//cout << endl;
for(int u = 1; u <= n; u++) {
for(int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if(col[u] != col[v]) {
link2(col[u], col[v]);
// print the new tree
//cout << col[u] << ' ' << col[v] << endl;
}
}
}
dfs1(1, 0); dfs2(1, 1);
cin >> q;
while(q--) {
int u, v; cin >> u >> v;
u = col[u], v = col[v];
int lca = get_lca(u, v);
//cout << dep[u] - dep[lca] + dep[v] - dep[lca] + 1 << endl;
print(dep[u] - dep[lca] + dep[v] - dep[lca] + 1);
cout << endl;
}
return 0;
}
标签:std,点双,树剖,int,top,wson,dep,while,P2783
来源: https://www.cnblogs.com/Garen-Wang/p/10349196.html
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。