Cod sursa(job #3225156)

Utilizator xXoctavianXxStanescu Matei Octavian xXoctavianXx Data 16 aprilie 2024 22:33:49
Problema Obiective Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.08 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("obiective.in");
ofstream fout("obiective.out");

const int nmax = 32003;
vector<int> g[nmax],rg[nmax];
vector<int> adj[nmax];
vector<int> aux;
int n,m,t;

int viz[nmax];
int color[nmax];
void dfs1(int i)
{
    if(viz[i] == 1) return;
    viz[i] = 1;
    for(auto pi : g[i])
    {
        dfs1(pi);
    }
    aux.push_back(i);
}

void dfs2(int i, int clr)
{
    if(viz[i] == 2) return;
    viz[i] = 2;
    color[i] = clr;
    for(auto pi : rg[i]) dfs2(pi,clr);
}

int root;
vector<int> toposort;
int grad[nmax];
int pos_in_toposort[nmax];

inline void sortare_topologica()
{
    queue<int> q;
    for(int i=1; i<=n; i++)
    {
        if(grad[i] == 0) q.push(i);
    }
    //cerr<<q.size();
    while(!q.empty())
    {
        int i = q.front();
        q.pop();
        //cerr<<i<<" ";
        toposort.push_back(i);
        for(auto pi : adj[i])
        {
            grad[pi] --;
            if(grad[pi] == 0)
            {
                q.push(pi);
            }
        }
    }
}

void sortTop(int i)
{
    if(viz[i]) return;
    viz[i] = 1;
    for(auto pi: adj[i]) sortTop(pi);
    toposort.push_back(i);
}

vector<int> verzi[nmax],rosii[nmax]; //muchii directe si muchii de intoarcere :)
int depth[nmax];

void dfs_depth(int i, int tata)
{
    if(depth[i] != 0) return;
    depth[i] = depth[tata] + 1;
    for(auto pi : adj[i])
    {
        dfs_depth(pi,i);
    }
}

const int pmax = 17;
int lift[nmax][pmax];

void dfs_build_tree(int i)
{
    for(auto pi : adj[i])
    {
        if(depth[pi] == depth[i] + 1)
        {
            verzi[i].push_back(pi);
            lift[pi][0] = i;
            dfs_build_tree(pi);
        }
    }
}

int tin[nmax],tout[nmax];
int timp = 0;
void dfs_lift(int i)
{
    tin[i] = timp ++;
    for(int p = 1; p < pmax; p++)
    {
        lift[i][p] = lift[lift[i][p-1]][p-1];
    }
    for(auto pi: verzi[i])
    {
        dfs_lift(pi);
    }
    tout[i] = timp ++;
}

bool is_ancestor(int nod, int tata)
{
    return tin[tata] <= tin[nod] && tout[nod] <= tout[tata];
}

int lca(int a, int b)
{
    if(is_ancestor(a,b)) return b;
    if(is_ancestor(b,a)) return a;
    ///plec din a
    for(int p = pmax - 1; p >= 0; p--)
    {
        if(!is_ancestor(b,lift[a][p]))
            a = lift[a][p];
    }
    return lift[a][0];
}

int dp[nmax][pmax]; ///tine deja minte minimul pe un subarbore

int best_depth(int a, int b)
{
    return depth[a] < depth[b] ? a : b;
}

void dfs_dp0(int i) ///o singura urcare
{
    for(auto pi: verzi[i]) dfs_dp0(pi);

    dp[i][0] = i;
    for(auto pi: rosii[i])
    {
        dp[i][0] = best_depth(pi,dp[i][0]);
    }
    for(auto pi: verzi[i])
    {
        dp[i][0] = best_depth(dp[i][0],dp[pi][0]);
    }
}

void dfs_dp(int i, int p)
{
    dp[i][p] = dp[dp[i][p-1]][p-1];
    for(auto pi: verzi[i])
    {
        dfs_dp(pi,p);
    }
}

int main()
{
    fin>>n>>m;
    for(int i=1; i<=m; i++)
    {
        int a,b; fin>>a>>b;
        g[a].push_back(b);
        rg[b].push_back(a);
    }
    for(int i=1; i<=n; i++) dfs1(i);
    reverse(aux.begin(),aux.end());
    int clr = 1;
    for(auto i: aux)
    {
        if(viz[i] == 2) continue;
        dfs2(i,clr);
        clr++;
    }
    clr --;
    map<pair<int,int> , bool> muchii;
    for(int i=1; i<=n; i++)
    {
        for(auto pi: g[i])
        {
            if(color[pi] == color[i]) continue;
            if(muchii[{color[i],color[pi]}] == 0)
            {
                muchii[{color[i],color[pi]}] = 1;
                adj[color[i]].push_back(color[pi]);
                rosii[color[pi]].push_back(color[i]);
                grad[pi] ++;
            }
        }
    }
    n = clr; ///conteaza numai graful restrans;
    //cerr<<"here";
    //sortare_topologica();

    for(int i=1; i<=n; i++)
    {
        if(rosii[i].size() == 0) root = i;
    }
    memset(viz,0,sizeof viz);
    sortTop(root);

    reverse(toposort.begin(),toposort.end());
    for(int i=0; i<n; i++) pos_in_toposort[toposort[i]] = i;
    for(int i=1; i<=n; i++)
    {
        sort(adj[i].begin(),adj[i].end(),[&](int a, int b) {return pos_in_toposort[a] < pos_in_toposort[b];});
    }
    ///build_tree
    dfs_depth(root,0);
    dfs_build_tree(root);
    lift[root][0] = root;
    dfs_lift(root); ///also build lca with tin and tout

    ///dp
    dfs_dp0(root);
    for(int p = 1; p<pmax; p++)
    {
        dfs_dp(root,p);
    }

    ///queries
    fin>>t;
    for(int i=1; i<=t; i++)
    {
        int a,b; fin>>a>>b; ///a - > b
        a = color[a]; b = color[b];

        int LCA = lca(a,b);
        if(LCA == a) fout<<"0\n";
        else
        {
            int cost_a = 0;
            for(int p = pmax - 1; p >=0; p--)
            {
                if(depth[dp[a][p]] > depth[LCA])
                {
                    cost_a += (1<<p);
                    a = dp[a][p];
                }
            }
            fout<<cost_a + 1<<"\n";
        }
    }
    return 0;
}