제출 #1166679

#제출 시각아이디문제언어결과실행 시간메모리
1166679xnqs늑대인간 (IOI18_werewolf)C++20
34 / 100
474 ms130088 KiB
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
#include <numeric>
#include "werewolf.h"
#include <cassert>
#include <functional>

template<typename Type>
class FenwickTree {
private:
	std::vector<Type> bit;
public:
	FenwickTree(int size = 0, Type val = 0) {
		Assign(size, val);
	}

	void Assign(int size = 0, Type val = 0) {
		bit.assign(size+1, 0);
		if (size&&val) {
			for (int i = 1; i < bit.size(); i++) {
				bit[i] += val;
				if (i+(i&-i)<bit.size()) {
					bit[i+(i&-i)] += bit[i];
				}
			}
		}
	}

	void Add(int pos, Type val) {
		while (pos < bit.size()) {
			bit[pos] += val;
			pos += pos&-pos;
		}
	}

	Type Query(int pos) {
		Type ret = 0;
		while (pos > 0) {
			ret += bit[pos];
			pos ^= pos&-pos;
		}
		return ret;
	}

	Type Query(int l, int r) {
		return Query(r) - Query(l-1);
	}
};

class DSU {
private:
	std::vector<int> t;
	std::vector<int> sz;
public:
	DSU(int n = 0) {
		t.assign(n, 0); std::iota(t.begin(),t.end(),0);
		sz.assign(n, 1);
	}

	int Find(int k) {
		if (t[k]!=k) return t[k] = Find(t[k]);
		return t[k];
	}

	int Unite(int a, int b) {
		a = Find(a);
		b = Find(b);
		
		if (a==b) {
			return 0;
		}
		if (sz[a]<sz[b]) {
			std::swap(a,b);
		}

		sz[a] += sz[b];
		t[b] = a;
		return 1;
	}

	int UniteExplicit(int a, int b) {
		a = Find(a);
		b = Find(b);
		
		if (a==b) {
			return 0;
		}

		sz[a] += sz[b];
		t[b] = a;
		return 1;
	}
};

struct Query {
	int l, r, pfx, idx, sgn;
	Query():
		l(0), r(0), pfx(0), idx(0), sgn(0) {}
	Query(int l, int r, int pfx, int idx, int sgn):
		l(l), r(r), pfx(pfx), idx(idx), sgn(sgn) {}
};

int gs, q;
std::vector<std::vector<int>> adj_list;

std::vector<std::vector<int>> krt_less;
std::vector<int> krt_less_tour;
int krt_less_tin[400005];
int krt_less_tout[400005];
int krt_less_depth[400005];
int krt_less_up[19][400005];

std::vector<std::vector<int>> krt_greater;
std::vector<int> krt_greater_tour;
int krt_greater_tin[400005];
int krt_greater_tout[400005];
int krt_greater_depth[400005];
int krt_greater_up[19][400005];

void build_krts() {
	// less
	std::vector<bool> active(gs+1, 0);
	DSU dsu(2*gs+5);
	for (int i = 0; i < gs; i++) {
		active[i] = 1;
		for (const auto& j : adj_list[i]) {
			if (active[j]) {
				int ri = dsu.Find(i);
				int rj = dsu.Find(j);

				if (ri!=rj) {
					dsu.UniteExplicit(ri, rj);
					krt_less[ri].emplace_back(rj);
					krt_less[rj].emplace_back(ri);

					//std::cout << ri << " " << rj << "\n";
				}
			}
		}
	}

	// greater
	active.assign(gs+1, 0);
	dsu = DSU(2*gs+5);
	for (int i = gs-1; i >= 0; i--) {
		active[i] = 1;
		for (const auto& j : adj_list[i]) {
			if (active[j]) {
				int ri = dsu.Find(i);
				int rj = dsu.Find(j);

				if (ri!=rj) {
					dsu.UniteExplicit(ri, rj);
					krt_greater[ri].emplace_back(rj);
					krt_greater[rj].emplace_back(ri);
					
					//std::cout << ri << " " << rj << "\n";
				}
			}
		}
	}
}

void process_krts() {
	const std::function<void(int, int, std::vector<std::vector<int>>&, std::vector<int>&, int*, int*, int*, int[19][400005])>
	dfs = [&](int k, int p, std::vector<std::vector<int>>& adj, std::vector<int>& tour, int* tin, int* tout, int* depth, int up[19][400005]) {
		tour.emplace_back(k);
		tin[k] = tour.size()-1;

		depth[k] = ((p==-1) ? 0 : depth[p]+1);
		up[0][k] = p;
		for (int j = 1; j < 19; j++) {
			up[j][k] = ((up[j-1][k]==-1) ? -1 : up[j-1][up[j-1][k]]);
		}

		for (const auto& i : adj[k]) {
			if (i==p) {
				continue;
			}

			depth[i] = depth[k]+1;
			up[0][i] = k;
			for (int j = 1; j < 19; j++) {
				up[j][i] = up[j-1][up[j-1][i]];
			}
			dfs(i, k, adj, tour, tin, tout, depth, up);
		}
		
		tout[k] = tour.size()-1;
	};

	dfs(gs-1, -1, krt_less, krt_less_tour, krt_less_tin, krt_less_tout, krt_less_depth, krt_less_up);
	dfs(0, -1, krt_greater, krt_greater_tour, krt_greater_tin, krt_greater_tout, krt_greater_depth, krt_greater_up);
}

int root_search_less(int node, int tgt) {
	for (int step = 18; step >= 0; step--) {
		if (krt_less_up[step][node] != -1 && (1<<step) <= krt_less_depth[node] && krt_less_up[step][node] <= tgt) {
			node = krt_less_up[step][node];
		}
	}
	return node;
}

int root_search_greater(int node, int tgt) {
	for (int step = 18; step >= 0; step--) {
		if (krt_greater_up[step][node] != -1 && (1<<step) <= krt_greater_depth[node] && krt_greater_up[step][node] >= tgt) {
			node = krt_greater_up[step][node];
		}
	}
	return node;
}

std::vector<int> solve_queries(std::vector<Query> queries) {
	std::sort(queries.begin(),queries.end(),[](const Query& a, const Query& b) {
		return a.pfx < b.pfx;
	});

	std::vector<int> ret(q, 0);
	std::vector<int> pos(2*gs+5, -1);
	for (int i = 0; i < krt_greater_tour.size(); i++) {
		pos[krt_greater_tour[i]] = i;
	}

	int scanline = 0;
	FenwickTree<int> fnwk(2*gs+5, 0);
	for (const auto& [ql, qr, qpfx, qidx, qsgn] : queries) {
		while (scanline <= qpfx) {
			//std::cout << pos[krt_less_tour[scanline]] << "\n";
			fnwk.Add(pos[krt_less_tour[scanline]]+1, 1);
			++scanline;
		}

		//std::cout << ql << " " << qr << " " << qpfx << " " << qidx << " " << qsgn << " " << fnwk.Query(ql+1,qr+1) << "\n";
		ret[qidx] += qsgn * fnwk.Query(ql+1, qr+1);
	}

	return ret;
}

std::vector<int> check_validity(int N, std::vector<int> X, std::vector<int> Y,
                                std::vector<int> S, std::vector<int> E,
                                std::vector<int> L, std::vector<int> R) {
	gs = N;
	q = S.size();
	adj_list.resize(gs+1);
	krt_less.resize(2*gs+5);
	krt_greater.resize(2*gs+5);

	for (int i = 0; i < gs-1; i++) {
		adj_list[X[i]].emplace_back(Y[i]);
		adj_list[Y[i]].emplace_back(X[i]);
	}

	build_krts();
	process_krts();

	std::vector<Query> queries;
	for (int i = 0; i < S.size(); i++) {
		if (S[i] < L[i] || E[i] > R[i]) {
			continue;
		}

		int root_human = root_search_greater(S[i], L[i]);
		int root_wolf = root_search_less(E[i], R[i]);

		int l1 = krt_greater_tin[root_human], r1 = krt_greater_tout[root_human];
		int l2 = krt_less_tin[root_wolf], r2 = krt_less_tout[root_wolf];

		queries.emplace_back(l1,r1,r2,i,1);
		if (l2-1>=0) {
			queries.emplace_back(l1,r1,l2-1,i,-1);
		}
	}

	std::vector<int> ret = solve_queries(queries);
	for (int i = 0; i < ret.size(); i++) {
		ret[i] = !!ret[i];
	}
	return ret;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...