Pagini recente » Cod sursa (job #374176) | Cod sursa (job #629804) | Cod sursa (job #374175) | Cod sursa (job #1704567) | Cod sursa (job #3307338)
#include <fstream>
#include <bitset>
#include <vector>
#include <queue>
#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) {
f[start] = 1;
for(auto nod : v[start]) { ///prima oara 'scoatem' muchiile si le salvam pe rosii
grad[nod]--;
if(grad[nod])
inv[nod].push_back(start);
}
for(auto nod : v[start]) {
if(!grad[nod] && !f[nod]) {///muchiile normale
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);
}
}
}
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
int root = 0;
void dfsaux(int start) { ///STRICT pt aux
if(start == root) ///init
sub[start] = root;
else
sub[start] = tata[start];
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;
}
}
///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) {
//cout << x.first << " " << x.second << '\n';
v[x.first].push_back(x.second);
grad[x.second]++;
}
for(int i = 1; i <= cnt; i++) {
if(grad[i] == 0) {
root = i;
break;
}
}
f = 0;
dfstree(root); ///alcatuim arborele (si separam si muchiile rosii si verzi)
dfsaux(root); ///calculam aux-ul
dfsdp(root); ///calculam dp-ul
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;
}
/*
14 18
1 2
2 4
2 5
5 6
5 7
5 8
8 14
1 4
2 8
1 3
3 9
9 10
9 11
11 12
12 13
3 10
9 13
11 13
0
*/