【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 (