Pagini recente » Cod sursa (job #3237079) | Statisticile problemei Football | Cod sursa (job #3230848) | Cod sursa (job #3287053) | Cod sursa (job #3281383)
#include<fstream>
#include<vector>
#include<bitset>
#include<set>
#include<algorithm>
#pragma GCC optimize("O3, unroll-loops")
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[4*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]);
}
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];
});
}
}
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();
dep[0]=0;
dep[st[0]]=1;
dfsTree(st[0], 0);
f.reset();
dfsJumps(st[0]);
}
inline void RMQ()
{
lg[0]=lg[1]=0;
for(int i=2; i<4*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();
kosaraju();
topSort();
makeTree();
RMQ();
solve();
return 0;
}