Submission #1138445

#TimeUsernameProblemLanguageResultExecution timeMemory
1138445dadas08Colors (RMI18_colors)C++20
0 / 100
138 ms150164 KiB
#include <bits/stdc++.h> #pragma GCC optimize("O3") #pragma GCC optimize("Ofast") #pragma GCC optimize("unroll-loops") // #include <ext/pb_ds/assoc_container.hpp> // #include <ext/pb_ds/tree_policy.hpp> // using namespace __gnu_pbds; // #define ordered_set tree<int, null_type, less<int>, rb_tree_tag,tree_order_statistics_node_update> // #define ordered_multiset tree<int, null_type, less_equal<int>, rb_tree_tag,tree_order_statistics_node_update> using namespace std; void _main(); int main() { cin.tie(0); ios::sync_with_stdio(false); _main(); return 0; } using ll = long long; using ull = unsigned long long; using ld = long double; using vi = std::vector<int>; using vvi = std::vector<vi>; using vl = std::vector<ll>; using vii = std::vector<pair<int, int> >; using vvl = std::vector<vl>; using vll = std::vector<pair<ll , ll> >; using vd = std::vector<double>; using vvd = std::vector<vd>; using vs = std::vector<std::string>; using vvs = std::vector<vs>; using vb = std::vector<bool>; using vvb = std::vector<vb>; using vc = std::vector<char>; using vvc = std::vector<vc>; using pii = std::pair<int, int>; using pll = std::pair<ll, ll>; using piil = std::pair<pair<int, int>, ll>; using mii = std::map<int, int>; using mll = std::map<ll, ll>; using pql = std::priority_queue<ll>; using pqi = std::priority_queue<int>; using pqiil = std::priority_queue<pair<pair<int, int>, ll> >; using pqii = std::priority_queue<pair<int, int> >; #define pb push_back #define ps push #define eb emplace_back #define is insert #define er erase #define f first #define s second #define lb lower_bound #define ub upper_bound #define sf(i) sizeof(i) #define endl "\n" #define all(v) (v).begin(), (v).end() #define rep(i, L, R) for(ll i = L;i<=R;i++) #define pcis precision #define sz(a) ((ll) a.size()) template<typename T> struct infinity { static constexpr T max=std::numeric_limits<T>::max(); static constexpr T min=std::numeric_limits<T>::min(); static constexpr T value=std::numeric_limits<T>::max()/2; static constexpr T mvalue=std::numeric_limits<T>::min()/2; }; template<typename T>constexpr T INF=infinity<T>::value; constexpr ll lINF=INF<ll>; constexpr int iINF = INF<int>; constexpr ld PI = 3.1415926535897932384626; struct UnionFindWithRollback { int par[300100]; // 루트라면 , -(트리의 크기) 를 저장. 아니라면 부모를 저장 stack<tuple<int,int,int>> S; UnionFindWithRollback() { memset(par, -1, sizeof(par)); } // O(log N) // 부모를 찾아 반환함 int find(int x) { if(par[x]<0) return x; return find(par[x]); } // O(log N) bool uni(int x, int y) { x = find(x), y = find(y); if(x == y) return false;// かわらず if(par[x] < par[y]) swap(x,y);// x가 항상 더 큼 -> x에 y를 달음 S.push({x, y, par[x]}); // 역추적 par[y] += par[x]; par[x] = y; return true; } // O(1) void rollback() { int x = get<0>(S.top()), y = get<1>(S.top()), sz = get<2>(S.top()); par[y] -= sz; par[x] = sz; S.pop(); } }; UnionFindWithRollback UF; vll tree[6010000]; // 분할정복 과정을 트리로 나타낸 것 vl col[300001]; ll N; //라이프타임이 s~e인 간선 u-v를 분할-정복 트리의 노드에 추가. (포함되면 추가) //조건 : l~r에 살아있는, 즉, s <= l && r <= e void init(int u, int v, int start, int end, int node, int left, int right) { if(end < left || right < start) return; if(start <= left && right <= end) { tree[node].pb({u, v}); return; } int mid = (left+right)/2; init(u, v, start, end, node*2, left, mid); init(u, v, start, end, node*2+1, mid+1, right); } bool CAN = true; void get(int node, int left, int right) { ll kawatta = 0; for(auto &p : tree[node]) kawatta += UF.uni(p.f, p.s);// 이 아래로 내려가면 이것들은 공통적으로 있으므로 추가해줌 //리프에 도달했으면, 현재 구간이 쿼리라면 출력 if(left == right) { for (auto i : col[left]) { if (UF.find(i) != UF.find(N + left)) { CAN = false; } } } if(left != right) { // 아래로 재귀 int mid = (left+right)/2; get(node*2, left, mid); get(node*2+1, mid+1, right); } //롤백 while(kawatta--) UF.rollback(); } // //void solve() { // // int N, M; // cin >> N >> M; // for(int i=0; i<M; ++i) { // for (int j = 0; j < 3; ++j) // cin >> query[i][j]; // if(query[i][1] > query[i][2]) // swap(query[i][1], query[i][2]); // } // map<pii, int> ikiru; // 각 간선이 생존해있는 시간 // for(int i=0; i<M; ++i) { // int &u = quer1y[i][1], &v = query[i][2]; // if(query[i][0] == 1) { //간선 추가 // ikiru[ {u, v}] = i;// i부터 살기 시작함 // } else if(query[i][0] == 2) { //간선 삭제 // int s = ikiru[ {u, v}];// s ~ i까지 살음 // init(u, v, s, i, 1, 0, M-1);// 간선을 트리에 박음 // ikiru.erase({u, v});// 그리고 D짐 // } // } // for(auto &p : ikiru) { // int u = p.f.f, v = p.f.s, s = p.s; // init(u, v, s, M-1, 1, 0, M-1);// 남은건 싹다 끝까지 산거임 // } // get(1, 0, M-1);// 풀면 됨 //} void _main() { ll T; cin >> T; while (T--) { ll N, M; cin >>N>>M; ::N = N; ll A[N+1], B[N+1]; CAN = true; rep(i,1,N) cin >> A[i]; rep(i,1,N) cin >> B[i]; rep(i,0,N*4) tree[i].clear(); for (ll i = 1; i<=M; i++) { ll a, b; cin >> a >> b; ll left = max(B[a], B[b]); ll right = min(A[a], A[b]); if (left <= right) init(a-1, b-1, left-1, right-1, 1, 0, N-1);// 저 시간동안에만 쓸 수 있음 } while (!UF.S.empty()) UF.S.pop(); rep(i,0,N) col[i].clear(); rep(i,1,N) col[B[i]-1].pb(i-1); rep(i,1,N) UF.uni(i-1, N + A[i]-1);// 그 색 -> 그 색을 가지는 친구 (기본으로 이정돈 해둠) get(1, 0, N-1); cout << CAN << endl; } }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...