답안 #627803

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
627803 2022-08-12T23:27:11 Z Noam527 송신탑 (IOI22_towers) C++17
0 / 100
689 ms 143544 KB
#include "towers.h"
#include <bits/stdc++.h>
const int OO = 0;
typedef long long ll;
using namespace std;

struct info {
	int len[2][2];
	int l, r;
	info(int x = -1, int i = 0) {
		len[0][0] = len[1][1] = -1e9;
		len[0][1] = len[1][0] = -1e9;
		l = 1e9, r = -1e9;
		if (x == 0) {
			l = r = i;
			len[0][0] = 1;
		}
		if (x == 1) {
			l = r = i;
			len[1][1] = 1;
		}
	}
	info operator * (const info &a) const {
		info res;
		res.l = min(l, a.l);
		res.r = max(r, a.r);
		for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) {
			res.len[i][j] = max(max(res.len[i][j], len[i][j]), a.len[i][j]);
		}
		for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) {
			res.len[i][k] = max(res.len[i][k], len[i][j] + a.len[1 ^ j][k]);
		}
		return res;
	}
	void print() {
		for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) {
			cout << i << " -> " << j << ": " << len[i][j] << '\n';
		}
	}
};
struct node {
	vector<pair<int, info>> data;
	node() {
		data.emplace_back(0, info());
	}
	void add(int tim, info i) {
		if (data.size() && data.back().first == tim)
			data.back().second = i;
		else
			data.emplace_back(tim, i);
	}
	info& get(int tim) {
		tim = max(tim, 0);
		int lo = 0, hi = (int)data.size() - 1, mid;
		while (lo < hi) {
			mid = (lo + hi + 1) / 2;
			if (data[mid].first <= tim) lo = mid;
			else hi = mid - 1;
		}
		return data[lo].second;
	}
};

struct segtree {
	int n;
	int tim;
	vector<node> t;
	vector<pair<int, int>> range;
	segtree() {}
	segtree(int sz) {
		tim = 0;
		n = max(2, sz);
		while (n != (n & -n)) n += (n & -n);
		t.resize(2 * n, node());
	}
	void advance_time(int newtim) {
		tim = newtim;
	}
	void fix(int x) {
		t[x].add(tim, t[2 * x + 1].get(tim) * t[2 * x + 2].get(tim));
	}
	void upd(int x, int val) {
		if (OO) cout << "upd " << x << " " << val << '\n';
		x += n - 1;
		t[x].add(tim, info(val, x - (n - 1)));
		while (x) {
			x = (x - 1) / 2;
			fix(x);
		}
	}
	int is_alive(int i, int T) {
		info tmp = t[i + n - 1].get(T);
		if (tmp.len[0][0] == 1 || tmp.len[1][1] == 1) return 1;
		return 0;
	}
	info query(int l, int r, int T) {
		if (l > r) return info();
		return query(l, r, T, 0, 0, n - 1);
	}
	info query(int l, int r, int T, int node, int nl, int nr) {
		if (nr < l || r < nl) return info();
		if (l <= nl && nr <= r) return t[node].get(T);
		int mid = (nl + nr) / 2;
		return query(l, r, T, 2 * node + 1, nl, mid) * query(l, r, T, 2 * node + 2, mid + 1, nr);
	}
};

struct superset {
	int n;
	vector<int> a;
	set<int> ind;
	set<pair<int, int>> q;
	superset() {}
	superset(const vector<int> &b) {
		a = b;
		n = a.size();
		for (int i = 0; i < n; i++)
			ind.insert(i);
		for (int i = 0; i < n; i++)
			q.emplace(abs(a[i] - a[i + 1]), i);
	}
	set<pair<int, int>>::iterator getq_element(set<int>::iterator it) {
		// assuming it exists
		return q.lower_bound(pair<int, int>(abs(a[*it] - a[*next(it)]), *it));
	}
	int upto(int R) {
		auto it = ind.upper_bound(R);
		if (it == ind.begin()) return -1;
		return *prev(it);
	}
	int atleast(int L) {
		auto it = ind.lower_bound(L);
		if (it == ind.end()) return 1e9;
		return *it;
	}
	// data kept between exchanges
	int last_min;
	set<int>::iterator last_i, last_j, last_k;

	int size() {
		return ind.size();
	}
	int get_min() {
		return last_min = q.begin()->first;
	}
	void get_triple() {
		auto p = *q.begin();
		auto it = ind.lower_bound(p.second);
		if (it == ind.begin())
			last_i = it;
		else
			last_i = prev(it);
		last_j = next(last_i);
		last_k = next(last_j);
	}
	void remove(int &removed_index, int &i, int &j) {
		int mx = max(max(a[*last_i], a[*last_j]), a[*last_k]);
		int mn = min(min(a[*last_i], a[*last_j]), a[*last_k]);
		int median = (ll)a[*last_i] + (ll)a[*last_j] + (ll)a[*last_k] - mn - mx;
		set<int>::iterator it;
		if (median == a[*last_i]) it = last_i;
		else if (median == a[*last_j]) it = last_j;
		else it = last_k;

		removed_index = *it;
		if (it == ind.begin()) i = -1;
		else i = *prev(it);
		if (next(it) == ind.end()) j = -1;
		else j = *next(it);

		// update q
		if (i == -1) {
			q.erase(getq_element(it));
		}
		else if (j == -1) {
			q.erase(getq_element(prev(it)));
		}
		else {
			q.erase(getq_element(prev(it)));
			q.erase(getq_element(it));
			q.insert(pair<int, int>(abs(a[i] - a[j]), i));
		}
		// update ind
		ind.erase(it);
	}
};

int n;
vector<int> h;
superset ind;

segtree T;

void init(int N, std::vector<int> H) {
	n = N;
	h = H;
	ind = superset(h);
	
	T = segtree(n);
	for (int i = 0; i + 1 < n; i++)
		if (h[i] < h[i + 1])
			T.upd(i, 0);
		else
			T.upd(i, 1);
	while (ind.size() > 2) {
		int d = ind.get_min();
		d = max(d, T.tim);
		T.advance_time(d);
		ind.get_triple();
		int index, li, ri;
		ind.remove(index, li, ri);
		T.upd(index, -1);
		if (li != -1) {
			if (ri == -1) {
				T.upd(li, -1);
			}
			else {
				if (h[li] < h[ri])
					T.upd(li, 0);
				else
					T.upd(li, 1);
			}
		}
		if (OO) {
			cout << "at d = " << d << ", remove li ri " << index << " " << li << " " << ri << '\n';
		}
	}
}

int bruteforce(int l, int r, int d) {
	int len = r - l + 1;
	int best = 0;
	for (int mask = 0; mask < (1 << len); mask++) {
		vector<int> val;
		for (int i = l; i <= r; i++) {
			if (mask & (1 << (i - l)))
				val.push_back(h[i]);
		}
		if (val.size() % 2 == 0) continue;
		bool good = true;
		for (int i = 0; i + 1 < val.size(); i++) {
			if (i % 2 == 0 && val[i] + d > val[i + 1]) good = false;
			if (i % 2 == 1 && val[i] - d < val[i + 1]) good = false;
		}
		if (good)
			best = max(best, (int)val.size() / 2 + 1);
	}
	return best;
}

int max_towers(int L, int R, int D) {
	int tim = D - 1;

	// fix L, R
	info q = T.query(L, R, tim);
	int l = q.l;
	int r = q.r;
	if (OO) {
		cout << "l r " << l << " " << r << '\n';
	}

	// break into cases - and also don't forget to consider the boundaries
	if (r < l) {
		// nothing in between - this is a monotonic range
		return 1;
	}
	q = T.query(l, r - 1, tim);
	if (OO) {
		cout << "from query received:\n";
		q.print();
	}
	if (L < l) {
		// consider left boundary
		info boundary = info();
		if (h[L] + D <= h[l])
			boundary = info(0);
		else if (h[L] - D >= h[l])
			boundary = info(1);
		q = boundary * q;
	}
	if (r < R) {
		// consider right boundary
		info boundary = info();
		if (h[r] + D <= h[R])
			boundary = info(0);
		else if (h[r] - D >= h[R])
			boundary = info(1);
		q = q * boundary;
	}
	return max(1, q.len[0][1] / 2 + 1);
}

Compilation message

towers.cpp: In function 'int bruteforce(int, int, int)':
towers.cpp:241:25: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  241 |   for (int i = 0; i + 1 < val.size(); i++) {
      |                   ~~~~~~^~~~~~~~~~~~
# 결과 실행 시간 메모리 Grader output
1 Runtime error 405 ms 84448 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 2 ms 848 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 2 ms 848 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 689 ms 143544 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 54 ms 18676 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 2 ms 848 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -
# 결과 실행 시간 메모리 Grader output
1 Runtime error 405 ms 84448 KB Execution killed with signal 6
2 Halted 0 ms 0 KB -