1+ #pragma GCC optimize("Ofast")
2+ #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
3+ #pragma GCC optimize("unroll-loops")
4+ #include < bits/stdc++.h>
5+ using namespace std ;
6+
7+ typedef long long ll;
8+ typedef vector<int > vi;
9+ #define fast_cin () \
10+ ios_base::sync_with_stdio (false ); \
11+ cin.tie(NULL ); \
12+ cout.tie(NULL );
13+
14+ int n, k;
15+ int e1 , e2 ;
16+
17+ vector<int > colour1, colour2;
18+ vector<vector<int >> adjlist1, adjlist2;
19+ vector<int > isOut1, isOut2;
20+
21+ void dfs (int u, int c, vector<int >& colour, vector<vector<int >>& adjlist) {
22+ colour[u] = c;
23+ for (int v : adjlist[u]) {
24+ if (colour[v] == -1 ) {
25+ dfs (v, (c + 1 ) % k, colour, adjlist);
26+ }
27+ }
28+ }
29+
30+ vector<pair<int , int >> countGoing (vector<int >& colour, vector<int >& isOut) { // returns {in, out} for each colour
31+ vector<pair<int , int >> going (k, {0 , 0 });
32+ for (int i = 0 ; i < n; i++) {
33+ if (isOut[i]) {
34+ going[colour[i]].second ++;
35+ } else {
36+ going[colour[i]].first ++;
37+ }
38+ }
39+ return going;
40+ }
41+
42+ typedef long long ll;
43+ ll mod (ll a, ll n) { return (a % n + n) % n; }
44+ int extEuclid (int a, int b, int & x, int & y) {
45+ ll xx = y = 0 ;
46+ ll yy = x = 1 ;
47+ while (b) { // repeats until b == 0
48+ ll q = a / b;
49+ tie (a, b) = tuple (b, a % b);
50+ tie (x, xx) = tuple (xx, x - q * xx);
51+ tie (y, yy) = tuple (yy, y - q * yy);
52+ }
53+ return a; // returns gcd(a, b)
54+ }
55+
56+ int modInverse (int b, int m) {
57+ int x, y;
58+ int d = extEuclid (b, m, x, y); // to get b*x + m*y == d
59+ if (d != 1 ) return -1 ; // to indicate failure
60+ // b*x + m*y == 1, now apply (mod m) to get b*x == 1 (mod m)
61+ return mod (x, m);
62+ }
63+
64+ template <int maxN = static_cast <int >(4e5 ), ll p = 131 , ll M = static_cast <int >(1e9 ) + 7 >
65+ class RollingHash {
66+ private:
67+ vector<ll> P, P_inv; // P[i] = p^i % M, P_inv[i] = (p^i)^-1 % M
68+
69+ vector<ll> H; // H[i] is the hash of prefix length i
70+ const int n;
71+ vector<int > T;
72+ void computeRollingHash () { // precompute H
73+ H.assign (n, 0 );
74+ for (int i = 0 ; i < n; i++) {
75+ if (i != 0 ) H[i] = H[i - 1 ];
76+ H[i] = (H[i] + ((ll)T[i] * P[i]) % M) % M;
77+ }
78+ }
79+
80+ void PrepareP () { // precompute P and P_inv
81+ P.assign (n, 0 );
82+ P[0 ] = 1 ;
83+ for (int i = 1 ; i < n; i++) P[i] = (P[i - 1 ] * p) % M;
84+
85+ P_inv.assign (n, 0 );
86+ P_inv[n - 1 ] = modInverse (P[n - 1 ], M);
87+ for (int i = n - 2 ; i >= 0 ; i--) P_inv[i] = (P_inv[i + 1 ] * p) % M;
88+ }
89+
90+ public:
91+ RollingHash (vector<int >& _s) : n(_s.size()), T(_s) {
92+ PrepareP ();
93+ computeRollingHash ();
94+ }
95+
96+ ll getHash (int l, int r) { // get hash of substring [l, r]
97+ if (l == 0 ) return H[r];
98+ ll ans = ((H[r] - H[l - 1 ]) % M + M) % M;
99+ ans = ((ll)ans * P_inv[l]) % M;
100+ return ans;
101+ }
102+ };
103+
104+ int main () {
105+ int tc;
106+ cin >> tc;
107+ while (tc--) {
108+ cin >> n >> k;
109+ isOut1.assign (n, 0 );
110+ isOut2.assign (n, 0 );
111+
112+ colour1.assign (n, -1 );
113+ colour2.assign (n, -1 );
114+
115+ adjlist1.assign (n, vector<int >());
116+ adjlist2.assign (n, vector<int >());
117+
118+ for (int i = 0 ; i < n; i++) cin >> isOut1[i];
119+
120+ cin >> e1 ;
121+ for (int i = 0 ; i < e1 ; i++) {
122+ int u, v;
123+ cin >> u >> v;
124+ u--;
125+ v--;
126+ adjlist1[u].push_back (v);
127+ }
128+
129+ for (int i = 0 ; i < n; i++) cin >> isOut2[i];
130+
131+ cin >> e2 ;
132+ for (int i = 0 ; i < e2 ; i++) {
133+ int u, v;
134+ cin >> u >> v;
135+ u--;
136+ v--;
137+ adjlist2[u].push_back (v);
138+ }
139+
140+ // edge case: if all nodes on one side are in and all nodes on the other side are out, accept
141+ bool allIn1 = true ;
142+ bool allOut1 = true ;
143+ for (int i = 0 ; i < n; i++) {
144+ if (isOut1[i]) {
145+ allIn1 = false ;
146+ } else {
147+ allOut1 = false ;
148+ }
149+ }
150+
151+ bool allIn2 = true ;
152+ bool allOut2 = true ;
153+ for (int i = 0 ; i < n; i++) {
154+ if (isOut2[i]) {
155+ allIn2 = false ;
156+ } else {
157+ allOut2 = false ;
158+ }
159+ }
160+
161+ if ((allIn1 && allOut2) || (allIn2 && allOut1)) {
162+ cout << " YES" << endl;
163+ continue ;
164+ }
165+
166+ dfs (0 , 0 , colour1, adjlist1);
167+ dfs (0 , 0 , colour2, adjlist2);
168+
169+ // we count the number of in going and out going edges of each colour in colour1 and colour2
170+
171+ vector<int > outs1, ins1, outs2, ins2;
172+
173+ vector<pair<int , int >> going1 = countGoing (colour1, isOut1);
174+ for (int i = 0 ; i < k; i++) {
175+ outs1.push_back (going1[i].second );
176+ ins1.push_back (going1[i].first );
177+ }
178+ for (int i = 0 ; i < k; i++) {
179+ outs1.push_back (going1[i].second );
180+ ins1.push_back (going1[i].first );
181+ }
182+ for (int i = 0 ; i < k; i++) {
183+ outs1.push_back (going1[i].second );
184+ ins1.push_back (going1[i].first );
185+ }
186+
187+ vector<pair<int , int >> going2 = countGoing (colour2, isOut2);
188+ for (int i = 0 ; i < k; i++) {
189+ outs2.push_back (going2[i].second );
190+ ins2.push_back (going2[i].first );
191+ }
192+
193+ RollingHash<> rhins1 (ins1), rhouts1 (outs1), rhins2 (ins2), rhouts2 (outs2);
194+
195+ ll hashins2 = rhins2.getHash (0 , k - 1 );
196+ ll hashouts2 = rhouts2.getHash (0 , k - 1 );
197+
198+ bool found = false ;
199+ for (int i = 0 ; i < k; i++) {
200+ ll hashouts1 = rhouts1.getHash (i, i + k - 1 );
201+ ll hashins1 = rhins1.getHash (i+2 , i + 2 + k - 1 );
202+
203+ if ( hashouts1 == hashins2 && hashins1 == hashouts2) {
204+ cout << " YES" << endl;
205+ found = true ;
206+ break ;
207+ }
208+ }
209+
210+ if (!found) {
211+ cout << " NO" << endl;
212+ }
213+ }
214+
215+ return 0 ;
216+ }
0 commit comments