제출 #1349336

#제출 시각아이디문제언어결과실행 시간메모리
1349336vladmart09Long Mansion (JOI17_long_mansion)C++20
100 / 100
203 ms58284 KiB
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <random>
#include <queue>
#include <numeric>
#include <array>
#include <iomanip>
#include <stack>
#include <chrono>
#include <climits>
#include <bitset>

using namespace std;

using ll = long long;
using ld = long double;
using vi = vector<ll>;
using vii = vector<vi>;
using viii = vector<vii>;
using pi = pair<ll, ll>;
using vpi = vector<pi>;
using vb = vector<bool>;
using vs = vector<string>;

#define vec vector
#define cmax(x, ...) x = max({x, __VA_ARGS__})
#define cmin(x, ...) x = min({x, __VA_ARGS__})
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()

const ll N = 5e5 + 5, MOD = 1e9 + 7, INF = (ll)1e18, K = 20;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

ll nxt[N], prv[N];

struct Seg {
	vi seg;

	Seg(ll n) {
		seg.assign(4 * n, INF);

		build(1, 1, n);
	}

	void build(ll t, ll tl, ll tr) {
		if (tl == tr) {
			seg[t] = prv[tl];
		}
		else {
			ll tm = tl + (tr - tl) / 2;

			build(t * 2, tl, tm);
			build(t * 2 + 1, tm + 1, tr);

			cmin(seg[t], seg[t * 2], seg[t * 2 + 1]);
		}
	}

	ll get(ll t, ll tl, ll tr, ll l, ll r, ll v) {
		if (tl > r || tr < l) return INF;
		
		if (seg[t] >= v) return INF;

		if (tl == tr) {
			return tl;
		}

		ll tm = tl + (tr - tl) / 2;

		ll res = get(t * 2, tl, tm, l, r, v);
		if (res != INF) return res;

		return get(t * 2 + 1, tm + 1, tr, l, r, v);
	}
};

void solve() {
	ll n; cin >> n;

	vi c(n + 1); for (ll i = 1; i < n; i++) cin >> c[i];
	
	vii a(n + 1);
	for (ll i = 1; i <= n; i++) {
		ll sz; cin >> sz;
		for (ll j = 0; j < sz; j++) {
			ll x; cin >> x;
			a[x].push_back(i);
		}
	}

	for (ll i = 1; i <= n; i++) {
		auto it = upper_bound(all(a[c[i]]), i);
		if (it == a[c[i]].end()) nxt[i] = n + 1;
		else nxt[i] = *it;

		if (it == a[c[i]].begin()) prv[i] = -1;
		else --it, prv[i] = *it;
	}

	stack<ll> st;

	Seg seg(n);
	vi l(n + 1), r(n + 1);

	for (ll i = 1; i <= n; i++) {
		l[i] = i;
		r[i] = min(n, seg.get(1, 1, n, i, n, l[i]));

		while (!st.empty()) {
			if (nxt[st.top()] > r[i]) break;

			auto cur = st.top(); st.pop();

			l[i] = l[cur];
			r[i] = min(n, seg.get(1, 1, n, i, n, l[i]));
		}

		st.push(i);
	}

	ll q; cin >> q;

	while (q--) {
		ll x, y; cin >> x >> y;

		if ((y >= x && r[x] >= y) || (y < x && l[x] <= y)) {
			cout << "YES\n";
		}
		else {
			cout << "NO\n";
		}
	}
}

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

	long long tt = 1;
	//cin >> tt;

	while (tt--) {
		solve();
		cout << '\n';
	}

	return 0;
}

/*



Я думаю что это препроцессинг до какой вершины может добраться итый элемент

Это дп с сег деревом для максимума

Идем с n до 1 элемента и держим сег дерево максимума. Допустим в данный момент мы знаем
что можем добраться до диапазона [l, r]. Можно сделать запрос на отрезке и перейти в 
следующий диапазон(увеличить правую границу). 





































Какие темы повторить:
1) мст
2) 2сат
3) точки артикуляции
4) ксор базис
5) эйлеровый цикл, путь
6) кмп
7) конвекс хулл
8) вафельное дерево
9) суфиксный массив
10) суффиксный автомат
11) ним

*/
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...