Pagini recente » Cod sursa (job #1002130) | Cod sursa (job #1819020) | Cod sursa (job #1529564) | Monitorul de evaluare | Cod sursa (job #3307321)
#include <fstream>
#include <bitset>
#include <vector>
#include <set>
using namespace std;
const int NMAX = 32000;
const int LOG = 16;
ifstream cin("obiective.in");
ofstream cout("obiective.out");
bitset <NMAX + 2> f;
void dfsctc(int start, vector <vector <int>>& adj, vector <int>& add_to) {
f[start] = 1;
for(auto nod : adj[start]) {
if(!f[nod])
dfsctc(nod, adj, add_to);
}
add_to.push_back(start);
}
vector <vector <int>> adj, inv;
vector <int> topo, aux;
int ctc[NMAX + 2]; ///fiec nod din ce comp de ctc apartine
set <pair <int, int>> edges; //noile muchii
vector <vector <int>> v; ///muchiile dintre ctc-uri
int tata[NMAX + 2], niv[NMAX + 2];
int up[NMAX + 2][LOG + 1];
int grad[NMAX + 2];
void dfstree(int start) {
for(auto nod : v[start]) {
grad[nod]--;
if(!grad[nod]) { ///muchie normala
tata[nod] = start;
niv[nod] = niv[start] + 1;
///build binary lifting pt lca
up[nod][0] = start;
for(int j = 1; j < LOG; j++)
up[nod][j] = up[up[nod][j - 1]][j - 1];
dfstree(nod);
}
else ///muchie rosie, o salvam
inv[nod].push_back(start);
}
}
int sub[NMAX + 2]; ///sub[nod] - pt subarborele lui nod, nodul cu niv maxim la care se poate ajunge
///dc luam o singura muchie de intoarcere (sau normala)
int dp[NMAX + 2][LOG + 1]; ///dp[i][j] - pt nodul i, nodul cel mai de sus la care poti ajunge,
///dc sari peste 2^j muchii in sus\
void dfsaux(int start) { ///STRICT pt aux
sub[start] = tata[start]; ///init
if(start == 1)
sub[start] = 1;
for(auto x : inv[start]) { ///toate muchiile de intoarcere care ajung in start
if(niv[x] < niv[sub[start]])
sub[start] = x;
}
for(auto nod : v[start]) {
if(tata[nod] == start) {
dfsaux(nod);
if(niv[sub[nod]] < niv[sub[start]])
sub[start] = sub[nod];
}
}
}
void dfsdp(int start) {
dp[start][0] = sub[start]; ///calc dp-ul
for(int j = 1; j < LOG; j++)
dp[start][j] = dp[dp[start][j - 1]][j - 1];
for(auto nod : v[start]) {
if(tata[nod] == start)
dfsdp(nod);
}
}
int LCA(int a, int b) {
if(niv[a] < niv[b])
swap(a, b);
int k = niv[a] - niv[b];
for(int j = LOG - 1; j >= 0; j--) {
if(k & (1 << j))
a = up[a][j];
}
if(a == b)
return a;
for(int j = LOG - 1; j >= 0; j--) {
if(up[a][j] != up[b][j]) {
a = up[a][j];
b = up[b][j];
}
}
return up[a][0];
}
int query(int a, int b) {
if(a == b)
return 0;
int ans = 1;
for(int j = LOG - 1; j >= 0; j--) {
if(niv[dp[a][j]] > niv[b]) {
ans += (1 << j);
a = dp[a][j];
}
}
return ans;
}
int main() {
int n, m;
cin >> n >> m;
///FORMAM CTC-URILE
adj.resize(n + 1);
inv.resize(n + 1);
for(int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
adj[a].push_back(b);
inv[b].push_back(a);
}
for(int i = 1; i <= n; i++) {
if(!f[i])
dfsctc(i, adj, topo);
}
f = 0;
int cnt = 0;
for(int i = n - 1; i >= 0; i--) {
if(!f[topo[i]]) {
aux.clear();
cnt++;
dfsctc(topo[i], inv, aux);
for(auto x : aux) ///egalam ctc-urile
ctc[x] = cnt;//, cout << x << " ";
//cout << '\n';
}
}
///GASIM NOILE MUCHII PE CARE LE FOLOSIM
for(int i = 1; i <= n; i++) {
for(auto nod : adj[i]) {
if(ctc[i] != ctc[nod])
edges.insert({ctc[i], ctc[nod]});
}
}
///ORDONAM MUCHIILE
v.resize(cnt + 1);
inv.clear();
inv.resize(cnt + 1);
for(auto x : edges) {
v[x.first].push_back(x.second);
grad[x.second]++;
}
dfstree(1); ///alcatuim arborele (si separam si muchiile rosii si verzi)
dfsaux(1); ///calculam aux-ul
dfsdp(1); ///calculam dp-ul
/*for(int i = 1; i <= cnt; i++)
cout << sub[i] << " ";
cout << '\n';
for(int i = 1; i <= cnt; i++) {
for(int j = 0; j < LOG; j++)
cout << dp[i][j] << " ";
cout << '\n';
}*/
int q;
cin >> q;
while(q--) {
int a, b;
cin >> a >> b;
a = ctc[a], b = ctc[b];
int lca = LCA(a, b);
//cout << a << " " << b << " " << lca << '\n';
cout << query(a, lca) << '\n';
}
return 0;
}