Cod sursa(job #3281387)

Utilizator MegaCoderMinoiu Teodor Mihai MegaCoder Data 1 martie 2025 11:41:38
Problema Obiective Scor 70
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.66 kb
#include<fstream>
#include<vector>
#include<bitset>
#include<set>
#include<algorithm>
#include<cassert>
std::ifstream fin("obiective.in");
std::ofstream fout("obiective.out");
const int NMAX=32005;
int n, m, t, nr;
std::vector<int>G[NMAX], tr[NMAX], srt[NMAX];//
std::vector<int>trDfs;//
std::set<int>SCC[NMAX];
std::vector<int>T(NMAX);//for SCC
std::bitset<NMAX>f;
std::vector<int>st;//

int lg[3*NMAX];
std::vector<int>priority(NMAX), firstOcc(NMAX, -1);
std::vector<int>dep(NMAX);
std::vector<std::pair<int, int>>eulerTour;//for dfs tree on SCC and for LCA
int dp[NMAX][15];
std::pair<int, int> rmq[NMAX][20];
inline void read()
{
    fin>>n>>m;
    for(int i=0; i<m; ++i)
    {
        int from, to;
        fin>>from>>to;
        G[from].push_back(to);
        tr[to].push_back(from);
    }
    fin>>t;
    std::fill(dp[0], dp[NMAX-1]+14, -1);
}
void dfsT(int node)
{
    f[node]=true;
    for(auto it:tr[node])
        if(!f[it])
            dfsT(it);
    trDfs.push_back(node);
}
void dfs(int node, int cnt)
{
    f[node]=true;
    T[node]=cnt;
    for(auto it:G[node])
        if(!f[it])
            dfs(it, cnt);
}
inline void kosaraju()
{
    int cnt=1;
    for(int i=1; i<=n; ++i)
        if(!f[i])
            dfsT(i);
    f.reset();
    for(int idx=(int)trDfs.size()-1; idx>=0; --idx)
        if(!f[trDfs[idx]])
        {
            dfs(trDfs[idx], cnt);
            ++cnt;
        }
    for(int i=1; i<=n; ++i)
    {
        tr[i].resize(0);
        for(auto j:G[i])
            if(T[i]!=T[j])
                SCC[T[i]].insert(T[j]);
        G[i].clear();
    }
    trDfs.clear();
    nr=cnt;
}
void topsortDfs(int node)
{
    f[node]=true;
    for(auto it:SCC[node])
        if(!f[it])
            topsortDfs(it);
    st.push_back(node);
}
inline void topSort()
{
    f.reset();
    for(int i=1; i<nr; ++i)
        if(!f[i])
            topsortDfs(i);

    std::reverse(st.begin(), st.end());
    for(int i=0; i<st.size(); ++i)
        priority[st[i]]=i;

    for(int i=1; i<nr; ++i)
    {
        for(auto it:SCC[i])
            srt[i].push_back(it);

        std::sort(srt[i].begin(), srt[i].end(), [&](int a, int b){
            return priority[a]<priority[b];
        });
        SCC[i].clear();
    }
    priority.clear();
}
void dfsTree(int node, int parent)
{
    if(dp[node][0]==-1 || dep[dp[node][0]]>dep[parent])
        dp[node][0]=parent;

    dep[node]=dep[parent]+1;
    eulerTour.emplace_back(dep[node], node);
    if(firstOcc[node]==-1)
        firstOcc[node]=(int)eulerTour.size()-1;

    f[node]=true;
    for(auto it:srt[node])
    {
        if(dp[it][0]==-1 || dep[node]<dep[dp[it][0]])
            dp[it][0]=node;
    }
    for(auto it:srt[node])
        if(!f[it])
        {
            dfsTree(it, node);
            eulerTour.emplace_back(dep[node], node);
            if(dep[dp[node][0]]>dep[dp[it][0]])
                dp[node][0]=dp[it][0];
        }
}
void dfsJumps(int node)
{
    f[node]=true;
    for(int p=1; p<15 && dp[dp[node][p-1]][p-1]!=-1; ++p)
        dp[node][p]=dp[dp[node][p-1]][p-1];

    for(auto it:srt[node])
        if(!f[it])
            dfsJumps(it);
}
void makeTree()
{
    f.reset();
    int first=st[0];
    st.clear();
    dep[0]=0;
    dep[first]=1;
    dfsTree(first, 0);
    f.reset();
    dfsJumps(first);
}
inline void RMQ()
{
    lg[0]=lg[1]=0;
    for(int i=2; i<3*NMAX; ++i)
        lg[i]=lg[i/2]+1;

    for(int i=0; i<eulerTour.size(); ++i)
        rmq[i][0]=eulerTour[i];

    for(int j=1; (1<<j)<eulerTour.size(); ++j)
        for(int i=0; i+(1<<j)-1<eulerTour.size(); ++i)
        {
            if(rmq[i][j-1].first<rmq[i+(1<<(j-1))][j-1].first)
                rmq[i][j]=rmq[i][j-1];
            else
                rmq[i][j]=rmq[i+(1<<(j-1))][j-1];
        }
}
inline int LCA(int a, int b)
{
    int start=firstOcc[a], end=firstOcc[b];
    if(start>end)
        std::swap(start, end);
    int dist=end-start+1;
    int d=lg[dist], rem=dist-(1<<d);
    if(rmq[start][d].first<rmq[start+rem][d].first)
        return rmq[start][d].second;
    return rmq[start+rem][d].second;
}
inline int getJumps(int node, int lca)
{
    if(node==lca)
        return 0;

    int jumps=0;
    int j=node;
    int d=lg[dep[j]];
    for(int aux=d; aux>=0; --aux)
        if(dp[j][aux]!=-1 && dep[dp[j][aux]]>dep[lca])
        {
            j=dp[j][aux];
            jumps+=(1<<aux);
        }
    return jumps+1;
}
inline int query(int a, int b)
{
    if(T[a]==T[b])
        return 0;
    a=T[a];
    b=T[b];
    int lca=LCA(a, b);
    return getJumps(a, lca);
}
void solve()
{
    while(t--)
    {
        int a, b;
        fin>>a>>b;
        fout<<query(a, b)<<'\n';
    }
}
int main()
{
    read();
    assert(n<NMAX);
    kosaraju();
    topSort();
    makeTree();
    RMQ();
    solve();
    return 0;
}