【USACO】USACO 2019 US Open Contest, Platinum题解

这篇博客详细解析了USACO 2019 US Open Contest铂金级别比赛的三道题目。第一题【T1】Tree Boxes通过在N×N网格构建特定树形结构,并利用LCA(最近公共祖先)求解。第二题【T2】Compound Escape采用基于连通性的动态规划,解决点的连通性问题,时间复杂度为O(NKS)。第三题【T3】Valleys利用并查集和高斯-波涅定理,判断山谷区域是否存在洞,时间复杂度为O(N^2LogN)或O(N^2α(N)+V)。
摘要由CSDN通过智能技术生成

【T1】 Tree Boxes

【题目链接】

【题解链接】

【思路要点】

  • 考虑在 N × N N\times N N×N 的网格内构建一个 N N N 个点的树,使得任意一个节点 x x x 与其任意一个祖先 y y y 所在位置为两角的矩形恰好包含 x x x y y y 路径上的所有点。
  • 以如下方式构造即可:
    ( 1 ) (1) (1) 、将根节点置于 ( 1 , 1 ) (1,1) (1,1)
    ( 2 ) (2) (2) 、对于一个根节点大小为 x x x 的子树,将其置于副对角线在 ( 2 , N ) − ( N , 2 ) (2,N)-(N,2) (2,N)(N,2) 上的大小为 x × x x\times x x×x 的矩形区域内,递归构造。
  • 构造完成之后简单求解 L C A LCA LCA 即可。
  • 时间复杂度 O ( N L o g N + Q L o g N ) O(NLogN+QLogN) O(NLogN+QLogN)

【代码】

#include "grader.h"
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXLOG = 20; 
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {
    x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {
    x = min(x, y); } 
int n, q, size[MAXN];
vector <int> a[MAXN];
int x[MAXN], y[MAXN];
int depth[MAXN], father[MAXN][MAXLOG];
void addRoad(int x, int y) {
    
	x++, y++;
	a[x].push_back(y);
	a[y].push_back(x);
}
int lca(int x, int y) {
    
	if (depth[x] < depth[y]) swap(x, y);
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (depth[father[x][i]] >= depth[y]) x = father[x][i];
	if (x == y) return x;
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (father[x][i] != father[y][i]) {
    
			x = father[x][i];
			y = father[y][i];
		}
	return father[x][0];
}
void dfs(int pos, int fa) {
    
	size[pos] = 1, depth[pos] = depth[fa] + 1;
	father[pos][0] = fa;
	for (int i = 1; i < MAXLOG; i++)
		father[pos][i] = father[father[pos][i - 1]][i - 1];
	for (auto x : a[pos])
		if (x != fa) {
    
			dfs(x, pos);
			size[pos] += size[x];
		}
}
void AssignPos(int pos, int fa, int nowx, int nowy) {
    
	x[pos] = nowx, y[pos] = nowy;
	nowx += size[pos] - 1, nowy += 1;
	for (auto x : a[pos])
		if (x != fa) {
    
			AssignPos(x, pos, nowx - size[x] + 1, nowy);
			nowx -= size[x];
			nowy += size[x];
		}
}
void buildFarms() {
    
	n = getN(), q = getQ();
	dfs(1, 0), AssignPos(1, 0, 1, 1);
	for (int i = 1; i <= n; i++)
		setFarmLocation(i - 1, x[i], y[i]);
}
void notifyFJ(int a, int b) {
    
	a++, b++;
	int c = lca(a, b);
	if (
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值