티스토리 뷰

문제

BOJ 16011 Min Max Tree

klimmek55 2019. 5. 24. 21:52

Min Max Tree

문제풀면서 이렇게 코드를 길게짜보긴 처음이다. 줄일 여지가 충분히 많긴 했지만 구현 연습하는셈치고 하나하나 다 짰다.

일단 어떤 경로 상에서 최솟값이 \(z\)라는 것은 그 경로상의 간선은 \(z\)이상이라는 의미다.
마찬가지로 최댓값이 주어지면 \(z\)이하라는 의미다.

그러면 이제 주어진 정보들을 가지고 모든 간선의 범위를 정할 수 있다. 문제는 어떤 경로 상의 구간의 최댓값과 최솟값을 업데이트해야한다는건데, 이거는 트리를 HLD로 나눈 뒤에 세그먼트 트리로 하면 된다.

그리고 모든 간선들의 범위를 정했다면, 원래 주어진 정보에 맞춰줘야 한다.
최솟값에 대한 정보였다면 그 경로에는 적어도 하나의 그 값이 있어야 한다.
이건 그리디하게? 하면 되는데,
각 정보 별로 값을 배정할 수 있는 간선들이 있을 것이다. 그러면 그 간선의 개수가 적은 것부터 배정할 수 있는 간선 중 아무거나 배정하면 된다.
만약 그 간선이 하나라면 무조건 그 간선에 값을 배정해야하므로 이 정보를 먼저 해결해야 한다.
그리고 그 간선이 두 개 이상이라면 배정할 수 있는 것 중 아무거나 배정해도 다른 정보 중에 하나에만 영향을 끼친다.
그러니까 아무거나 되는 것 중에서 골라도 상관없다.

그래서 짠게 LCA, HLD, 세그먼트트리 + Lazy Propagation라서 코드가 엄청 길어졌다. 근데 다른 분들 코드를 보니까 이분 매칭으로도 풀리는 것 같기도 하다.

#include <bits/stdc++.h>

using namespace std;

const int ninf = -2e9, pinf = 2e9;

struct Qry {
	bool mx;
	int u, v, w;
};

vector<int> gph[70001], rng[70001];
Qry qry[70001];
int n, dep[70001], subsz[70001], ord[70001], num, par[70001][20], chain[70001], chainhead[70001], chainnum, mnlazy[500000], mntree[500000], mxlazy[500000], mxtree[500000], cnt[70001], low[70001], high[70001], ans[70001], rord[70001];
bool comp[70001], compans[70001];

int f(int now, int d) {
	dep[now] = d;
	subsz[now] = 1;

	for (int i = 1; i < 20; ++i)
		par[now][i] = par[par[now][i - 1]][i - 1];

	for (int nxt : gph[now])
		if (nxt != par[now][0]) {
			par[nxt][0] = now;
			subsz[now] += f(nxt, d + 1);
		}

	return subsz[now];
}

void mkchain(int now) {
	ord[now] = ++num;
	chain[now] = chainnum;

	int heavy = 0, heavyi = -1;
	for (int nxt : gph[now])
		if (nxt != par[now][0] && heavy < subsz[nxt]) {
			heavy = subsz[nxt];
			heavyi = nxt;
		}

	if (heavyi != -1)
		mkchain(heavyi);

	for (int nxt : gph[now])
		if (nxt != par[now][0] && nxt != heavyi) {
			chainnum++;
			chainhead[chainnum] = nxt;
			mkchain(nxt);
		}
}

int lca(int u, int v) {
	if (dep[u] < dep[v])
		swap(u, v);

	for (int i = 19; i >= 0; --i)
		if (dep[par[u][i]] >= dep[v])
			u = par[u][i];

	if (u == v)
		return u;

	for (int i = 19;i >= 0;--i)
		if (par[u][i] != par[v][i]) {
			u = par[u][i];
			v = par[v][i];
		}

	return par[u][0];
}

void lazymn(int l, int r, int idx) {
	mntree[idx] = max(mntree[idx], mnlazy[idx]);

	if (l != r) {
		mnlazy[idx * 2] = max(mnlazy[idx * 2], mnlazy[idx]);
		mnlazy[idx * 2 + 1] = max(mnlazy[idx * 2 + 1], mnlazy[idx]);
	}

	mnlazy[idx] = ninf;
}

int updmn(int l, int r, int idx, int s, int e, int val) {
	lazymn(l, r, idx);

	if (e < l || r < s)
		return mntree[idx];
	if (s <= l && r <= e) {
		mntree[idx] = max(mntree[idx], val);
		if (l != r) {
			mnlazy[idx * 2] = max(mnlazy[idx * 2], val);
			mnlazy[idx * 2 + 1] = max(mnlazy[idx * 2 + 1], val);
		}
		return mntree[idx];
	}
	
	int m = (l + r) / 2;
	return mntree[idx] = max(updmn(l, m, idx * 2, s, e, val), updmn(m + 1, r, idx * 2 + 1, s, e, val));
}

int qrymn(int l, int r, int idx, int s, int e) {
	lazymn(l, r, idx);

	if (e < l || r < s)
		return ninf;
	if (s <= l && r <= e)
		return mntree[idx];

	int m = (l + r) / 2;
	return max(qrymn(l, m, idx * 2, s, e), qrymn(m + 1, r, idx * 2 + 1, s, e));
}

void lazymx(int l, int r, int idx) {
	mxtree[idx] = min(mxtree[idx], mxlazy[idx]);
	if (l != r) {
		mxlazy[idx * 2] = min(mxlazy[idx * 2], mxlazy[idx]);
		mxlazy[idx * 2 + 1] = min(mxlazy[idx * 2 + 1], mxlazy[idx]);
	}

	mxlazy[idx] = pinf;
}

int updmx(int l, int r, int idx, int s, int e, int val) {
	lazymx(l, r, idx);
	if (e < l || r < s)
		return mxtree[idx];
	if (s <= l && r <= e) {
		mxtree[idx] = min(mxtree[idx], val);
		if (l != r) {
			mxlazy[idx * 2] = min(mxlazy[idx * 2], val);
			mxlazy[idx * 2 + 1] = min(mxlazy[idx * 2 + 1], val);
		}
		return mxtree[idx];
	}

	int m = (l + r) / 2;
	return mxtree[idx] = min(updmx(l, m, idx * 2, s, e, val), updmx(m + 1, r, idx * 2 + 1, s, e, val));
}

int qrymx(int l, int r, int idx, int s, int e) {
	lazymx(l, r, idx);
	if (e < l || r < s)
		return pinf;
	if (s <= l && r <= e)
		return mxtree[idx];

	int m = (l + r) / 2;
	return min(qrymx(l, m, idx * 2, s, e), qrymx(m + 1, r, idx * 2 + 1, s, e));
}

void mkrange(int u, int v, bool mx, int val) {
	if (dep[u] < dep[v])
		swap(u, v);

	if (u == v)
		return;

	if (chain[u] == chain[v]) {
		if (mx)
			updmx(1, n, 1, ord[v] + 1, ord[u], val);
		else
			updmn(1, n, 1, ord[v] + 1, ord[u], val);
	}
	else {
		if (mx) {
			updmx(1, n, 1, ord[chainhead[chain[u]]], ord[u], val);
			mkrange(par[chainhead[chain[u]]][0], v, mx, val);
		}
		else {
			updmn(1, n, 1, ord[chainhead[chain[u]]], ord[u], val);
			mkrange(par[chainhead[chain[u]]][0], v, mx, val);
		}
	}
}

int main() {
	scanf("%d", &n);

	for (int i = 1; i <= n - 1; ++i) {
		int u, v;
		scanf("%d %d", &u, &v);

		gph[u].push_back(v);
		gph[v].push_back(u);
	}

	int k;
	scanf("%d", &k);

	for (int i = 1; i <= k; ++i) {
		char c;
		scanf(" %c %d %d %d", &c, &qry[i].u, &qry[i].v, &qry[i].w);

		if (c == 'M')
			qry[i].mx = true;
		else
			qry[i].mx = false;
	}

	f(1, 1);
	chainnum++;
	chainhead[chainnum] = 1;
	mkchain(1);

	for (int i = 0; i < 500000; ++i) {
		mnlazy[i] = ninf;
		mntree[i] = ninf;
		mxlazy[i] = pinf;
		mxtree[i] = pinf;
	}

	for (int i = 1; i <= k; ++i) {
		int l = lca(qry[i].u, qry[i].v);

		mkrange(qry[i].u, l, qry[i].mx, qry[i].w);
		mkrange(qry[i].v, l, qry[i].mx, qry[i].w);
	}

	map<int, int> dic;
	for (int i = 1; i <= k; ++i)
		dic[qry[i].w] = i;
	for (int i = 2; i <= n; ++i) {
		low[i] = qrymn(1, n, 1, i, i);
		high[i] = qrymx(1, n, 1, i, i);

		if (low[i] != ninf) {
			cnt[dic[low[i]]]++;
			rng[dic[low[i]]].push_back(i);
		}
		if (high[i] != pinf) {
			cnt[dic[high[i]]]++;
			rng[dic[high[i]]].push_back(i);
		}
	}

	priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq;
	for (int i = 1; i <= k; ++i)
		pq.push({ cnt[dic[qry[i].w]], i });
	while (!pq.empty()) {
		pair<int, int> now = pq.top();
		pq.pop();

		if (now.first != cnt[now.second])
			continue;

		comp[now.second] = true;

		for (int cand : rng[now.second])
			if (!compans[cand]) {
				ans[cand] = qry[now.second].w;
				compans[cand] = true;
				if (qry[now.second].mx) {
					if (low[cand] != ninf) {
						cnt[dic[low[cand]]]--;

						if (!comp[dic[low[cand]]])
							pq.push({ cnt[dic[low[cand]]], dic[low[cand]] });
					}
				}
				else {
					if (high[cand] != pinf) {
						cnt[dic[high[cand]]]--;

						if (!comp[dic[high[cand]]])
							pq.push({ cnt[dic[high[cand]]], dic[high[cand]] });
					}
				}

				break;
			}
	}

	for (int i = 2; i <= n; ++i)
		if (!compans[i]) {
			ans[i] = low[i];
			compans[i] = true;
		}

	for (int i = 1; i <= n; ++i)
		rord[ord[i]] = i;

	for (int i = 2; i <= n; ++i)
		printf("%d %d %d\n", rord[i], par[rord[i]][0], ans[i]);

	return 0;
}

'문제' 카테고리의 다른 글

POJ 3904 Sky Code  (0) 2019.08.21
CodeChef Simple Sum  (0) 2019.08.19
BOJ 2066 카드놀이  (0) 2019.02.18
BOJ 1739 도로 정비하기  (0) 2019.01.13
BOJ 2454 트리 분할  (0) 2018.12.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함