洛谷 P2783 有机化学之神偶尔会做作弊(Tarjan+無向圖縮點+LCA)

思路:
先用 T a r j a n Tarjan Tarjan對原圖進行一個縮點,然後建一個圖,然後處理一下樹上的點距,求一下 L c a Lca Lca即可

參考代碼:

/*
 * @Author: vain
 * @Date: 2020-08-26 11:58:46
 * @LastEditTime: 2020-09-08 18:01:56
 * @LastEditors: sueRimn
 * @Description: In User Settings Edit
 * @FilePath: \main\demo.cpp
 */
//#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
//#define ll long long
typedef unsigned long long ull;
const int N = 1e3 + 20;
const ll maxn = 1e5 + 20;
const ll mod = 1e9 + 7;
int head[maxn], stac[maxn], vis[maxn], depth[maxn], pre[maxn][32];
int dis[maxn], dfn[maxn], low[maxn], sg[maxn];
//typedef pair p;
//priority_queue, greater

> m; //ll sum[maxn]; int max(int a, int b) { return a > b ? a : b; } ll min(ll a, ll b) { return a < b ? a : b; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } ll lcm(ll a, ll b) { return a * b / gcd(a, b); } void swap(ll &x, ll &y) { x ^= y, y ^= x, x ^= y; } map<string, ll> pll, che, mp; int us[maxn], vs[maxn], cnt, top, ans, ti; int lowbit(int x) { return (x) & (-x); } vector<int> fc; //ull h[maxn], p[maxn]; const ull base = 13331; //char s1[maxn]; ll ksm(ll a, ll b) { ll res = 1; while (b) { if (b & 1) res = a * res; b >>= 1; a = a * a; } return res; } struct node { int v, nex; } edge[maxn << 1]; void add(int u, int v) { edge[cnt].v = v, edge[cnt].nex = head[u]; head[u] = cnt++; } void tarjan(int u, int fa) { low[u] = dfn[u] = ++ti; stac[top++] = u, vis[u] = 1; for (int i = head[u]; ~i; i = edge[i].nex) { int v = edge[i].v; if (v != fa) { if (!dfn[v]) { tarjan(v, u); low[u] = min(low[v], low[u]); } else if (vis[v]) { low[u] = min(low[u], dfn[v]); } } } if (low[u] == dfn[u]) { ans++; while (top && stac[top] != u) { --top; int x = stac[top]; sg[x] = ans, vis[x] = 0; } } } void dfs(int u, int fa) //求深度 { depth[u] = depth[fa] + 1; pre[u][0] = fa; for (int i = 1; (1 << i) <= depth[u]; i++) pre[u][i] = pre[pre[u][i - 1]][i - 1]; for (int i = head[u]; ~i; i = edge[i].nex) { int v = edge[i].v; if (fa != v) { dis[v] = dis[u] + 1; dfs(v, u); } } } int lca(int u, int v) { if (depth[u] < depth[v]) swap(u, v); //让u的深度大 int i = -1, j; while ((1 << (i + 1)) <= depth[u]) //从u跨到根节点的跨度 i++; for (j = i; j >= 0; j--) //同一水平 { if (depth[u] - (1 << j) >= depth[v]) { u = pre[u][j]; } } if (u == v) { return u; } for (j = i; j >= 0; j--) { if (pre[u][j] != pre[v][j]) { u = pre[u][j]; v = pre[v][j]; } } return pre[u][0]; } void solv(int x) { bool ok = false; for (int i = 31; ~i; i--) { if ((x >> i) & 1) { cout << 1; ok = true; } else if (ok) { cout << 0; } } cout << endl; } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); srand(time(NULL)); //cout << ksm(2, 20) << endl; int n, m, u, v, q; // cin >> t;zz // while (t--) // { // } memset(head, -1, sizeof head); cin >> n >> m; for (int i = 0; i < m; i++) cin >> u >> v, add(u, v), add(v, u), us[i] = u, vs[i] = v; for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i, 0); } cnt = 0; memset(head, -1, sizeof head); for (int i = 0; i < m; i++) { if (sg[us[i]] != sg[vs[i]]) add(sg[us[i]], sg[vs[i]]), add(sg[vs[i]], sg[us[i]]); } dis[sg[1]] = 1; dfs(sg[1], 0); cin >> q; while (q--) { cin >> u >> v; int Lca = lca(sg[u], sg[v]); int ia = dis[sg[u]] + dis[sg[v]] - 2 * dis[Lca] + 1; solv(ia); } }

你可能感兴趣的:(洛谷 P2783 有机化学之神偶尔会做作弊(Tarjan+無向圖縮點+LCA))