Submission #1293903

#TimeUsernameProblemLanguageResultExecution timeMemory
1293903shidou26Joker (BOI20_joker)C++20
100 / 100
256 ms21708 KiB
#include <bits/stdc++.h>
using namespace std;

#ifdef KURUMI
    #include "algo/debug.h"
#endif

#define endl '\n'
#define fi first
#define se second
#define sz(v) (int)v.size()
#define all(v) v.begin(), v.end()
#define filter(v) v.resize(unique(all(v)) - v.begin())
#define dbg(x) "[" #x << " = " << x << "]" 

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
template<typename T1, typename T2> T2 rand(T1 l, T2 r) {
    return uniform_int_distribution<T2>(l, r)(rng);
}
template<typename T1, typename T2> T2 wrand(T1 l, T2 r, int seed) {
    if(seed == 0) return rand(l, r);
    else return (seed > 0 ? max(rand(l, r), wrand(l, r, seed - 1)) : min(rand(l, r), wrand(l, r, seed + 1)));
}

template<typename T> bool maximize(T &a, T b) {
    if(a < b) {
        a = b;
        return true; 
    }else return false;
}
template<typename T> bool minimize(T &a, T b) {
    if(a > b) {
        a = b;
        return true;
    }else return false;
}

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tp3;

const int N = 2e5 + 3;

int n, m, q;
int l[N], r[N];
struct Edge {int u, v;} edge[N];

void input() {
	cin >> n >> m >> q;

	for(int i = 1; i <= m; i++) {
		cin >> edge[i].u >> edge[i].v;
	}

	for(int i = 1; i <= q; i++) {
		cin >> l[i] >> r[i];
	}
}

struct UnionFind {
	int bipartite;
	vector<int> lab, save;
	vector<pair<int&, int>> history;

	UnionFind (int n) : bipartite(1), lab(2 * n + 3) {
		for(int i = 1; i <= 2 * n; i++) {
			lab[i] = -1;
		}
	}

	int root(int u) {
		return lab[u] < 0 ? u : root(lab[u]);
	}

	bool unite(int u, int v) {
		u = root(u); v = root(v);
		if(u == v) return false;
		if(lab[u] > lab[v]) swap(u, v);
		history.emplace_back(lab[u], lab[u]);
		history.emplace_back(lab[v], lab[v]);
		lab[u] += lab[v];
		lab[v] = u;
		return true;
	}

	void clause(int u, int v) {
		// cout << "Adding " << dbg(u) << dbg(v) << endl;

		// u and v with different sides
		unite(u, v + n);
		unite(v, u + n);

		// bipartite false 
		if(root(u) == root(u + n) || root(v) == root(v + n)) {
			history.emplace_back(bipartite, bipartite);
			bipartite = 0;
		} 
	}

	void persist() {save.push_back(sz(history));}
	void rollback() {
		// cout << "Removing " << endl;
		int t = save.back(); save.pop_back();
		while(t < sz(history)) {
			// cout << history.back().fi << " " << history.back().se << endl;
			history.back().fi = history.back().se;
			history.pop_back();
		}
	}
};

namespace subtask_2 {
	bool approve() {
		return max({n, m, q}) <= 2000;
	}

	void execute() {
		UnionFind dsu(n);
		for(int i = 1; i <= q; i++) {
			// cout << dsu.bipartite << " " << sz(dsu.history) << " " << sz(dsu.save) << endl;
			dsu.persist();
			// for(int j = 1; j <= n; j++) cout << dsu.root(j) << " \n"[j == n];
			for(int j = 1; j < l[i]; j++) dsu.clause(edge[j].u, edge[j].v);
			for(int j = r[i] + 1; j <= m; j++) dsu.clause(edge[j].u, edge[j].v);
			cout << (!dsu.bipartite ? "YES" : "NO") << endl;
			dsu.rollback();
		}
	}
}

namespace subtask_5 {
	bool approve() {
		return q <= 1000;
	}

	namespace Block {
		const int S = 2000;

		int block(int id) {
			return (id - 1) / S + 1;
		}

		int low(int id) {
			return (id - 1) * S + 1;
		}

		int up(int id) {
			return min(m, id * S);
		}
	} 
	using namespace Block;

	bool answer[N];
	vector<int> query[N];

	void execute() {
		UnionFind dsu(n);

		for(int i = 1; i <= q; i++) {
			if((l[i] - 1) + (m - r[i]) <= S) {
				dsu.persist();
				for(int j = 1; j < l[i]; j++) dsu.clause(edge[j].u, edge[j].v);
				for(int j = r[i] + 1; j <= m; j++) dsu.clause(edge[j].u, edge[j].v);
				answer[i] = !dsu.bipartite;
				dsu.rollback();
				continue;
			}

			query[block(l[i])].emplace_back(i);
		}

		int num_block = block(m);

		for(int b = 1, lpt = 1; b <= num_block; b++) {
			if(query[b].empty()) continue;
			sort(all(query[b]), [&](int x, int y) {
				return r[x] > r[y];
			});	

			// cout << dbg(b) << endl;
			// cout << dbg(query[b]) << endl;

			int lft = low(b);
			int pointer = m;

			while(lpt < lft) {
				dsu.clause(edge[lpt].u, edge[lpt].v);
				lpt++;
			}

			dsu.persist();
			for(int i : query[b]) {
				while(r[i] < pointer) {
					dsu.clause(edge[pointer].u, edge[pointer].v);
					pointer--;
				}

				dsu.persist();
				for(int j = lft; j < l[i]; j++) dsu.clause(edge[j].u, edge[j].v);
				answer[i] = !dsu.bipartite;
				dsu.rollback();
			}
			dsu.rollback();
		}

		for(int i = 1; i <= q; i++) {
			cout << (answer[i] ? "YES" : "NO") << endl;
		}
	}
}

namespace subtask_6 {
	bool approve() {
		return true;
	}

	int last[N];

	void solve(int l, int r, int opt_l, int opt_r, UnionFind &dsu) {
		if(l > r) return;	
		int mid = (l + r) >> 1;

		dsu.persist();
		for(int i = l; i < mid; i++) {
			dsu.clause(edge[i].u, edge[i].v);
		}

		dsu.persist();
		last[mid] = mid;
		if(!dsu.bipartite) last[mid] = opt_r;
		else {
			for(int i = opt_r - 1; i >= mid; i--) {
				dsu.clause(edge[i].u, edge[i].v);
				if(!dsu.bipartite) {
					last[mid] = i;
					break;
				}
			}
		} 

		dsu.rollback();
		dsu.clause(edge[mid].u, edge[mid].v);
		solve(mid + 1, r, last[mid], opt_r, dsu);

		dsu.rollback();
		for(int i = opt_r - 1; i >= last[mid]; i--) dsu.clause(edge[i].u, edge[i].v);
		solve(l, mid - 1, opt_l, last[mid], dsu);
	}

	void execute() {
		UnionFind dsu(n);
		solve(1, m, 1, m + 1, dsu);

		// for(int i = 1; i <= n; i++) cout << last[i] << " \n"[i == n];
		for(int i = 1; i <= q; i++) {
			cout << (r[i] < last[l[i]] ? "YES" : "NO") << endl;
		}
	}
}

void process() {
    if(subtask_2::approve()) return subtask_2::execute();
    if(subtask_5::approve()) return subtask_5::execute();
    if(subtask_6::approve()) return subtask_6::execute();
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    #define task "Deeto"
    if(fopen(task".inp", "r")) {
        freopen(task".inp", "r", stdin);
        freopen(task".out", "w", stdout);
    }
    
    int testcase = 1; // cin >> testcase;    
    for(int i = 1; i <= testcase; i++) {
        input();
        process();
    }

    cerr << "Saa, watashtachi no deeto hajimemashou" << endl;
    cerr << "Atarashii kiseki wo koko kara hajimeru shining place nee mou ichido kimi to..." << endl;
    
    return 0;
}

Compilation message (stderr)

Joker.cpp: In function 'int main()':
Joker.cpp:276:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  276 |         freopen(task".inp", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
Joker.cpp:277:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  277 |         freopen(task".out", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
#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...