주제 요약
주어진 \ (\ N-) 포인트 \ (m의 \) 의 그래프는, 소정 방향 가장자리가 \ (Q \) 기 질의, 주어진 각 쿼리 \ (S, T, L \) , 요청을 하나가 \ (S \)은 하기 (T \) \ 직후 경로 \ (L의 \) 측이, 패스가 반복 될 수있다 간다.
\ (N 르 100 m를 \ \ 르 10000, Q \ 르 1000 L \ 르 10 ^ 9 \)
문제 해결 아이디어
사전 배열 고려 (F [X] [I] [J] \)는 \ 여부를 나타내는을 : \ (I는 \)의 온 \ (J \) 후 \ (2 ^ k 개의 \) 가장자리.
이것은 바로 우리가에서 두 배 고려할 수, 플로이드를 곱 실행할 수 있습니다 \ (들의 \) 일부 노드만큼 판사 확장 한 각 BFS의 시작 \ (t의 \)를 노드의 마지막 세트에 속한다.
세부 사항
- 다른 방법은 종종 동화와 같은 카드를 요구할 수있다 \ (O (\ FRAC {N ^ 3} {64}의 Q \ log_의 {256} l) \)
참조 코드
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cmath>
#include <ctime>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < typename T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
s = f ? -s : s;
}
const int _ = 102;
int n, m, f[31][_][_], vis[_];
vector < int > vec;
inline void expand(int x) {
memset(vis, 0, sizeof (int) * (n + 1));
for (rg int i = 1; i <= n; ++i)
for (rg int j = 0; j < vec.size(); ++j)
if (f[x][vec[j]][i]) { vis[i] = 1; break; }
vec.clear();
for (rg int i = 1; i <= n; ++i) if (vis[i]) vec.push_back(i);
}
inline void solve() {
int l, x, y; read(l), read(x), read(y);
vec.clear(); vec.push_back(x);
for (rg int i = 30; ~i; --i)
if (l >> i & 1) expand(i);
for (rg int i = 0; i < vec.size(); ++i)
if (vec[i] == y) { puts("YES"); return; }
puts("NO");
}
int main() {
// file("cave");
read(n), read(m);
for (rg int u, v, i = 1; i <= m; ++i)
read(u), read(v), f[0][u][v] = 1;
for (rg int x = 1; x <= 30; ++x)
for (rg int k = 1; k <= n; ++k)
for (rg int i = 1; i <= n; ++i)
for (rg int j = 1; j <= n; ++j)
f[x][i][j] |= f[x - 1][i][k] & f[x - 1][k][j];
int T; read(T);
while (T--) solve();
return 0;
}
끝 일러스트 sahua \ (qwq \)