洛谷 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 <bits/stdc++.h>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <math.h>
#include <bitset>
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<ll, ll> p;
//priority_queue<p, vector<p>, greater<p> > 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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值