Skip to content

Commit

Permalink
Merge pull request yosupo06#1267 from maspypy/1258
Browse files Browse the repository at this point in the history
テストケース追加 1258
  • Loading branch information
maspypy authored Nov 27, 2024
2 parents 7a31121 + 5a8d2e4 commit be0862b
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 0 deletions.
247 changes: 247 additions & 0 deletions tree/jump_on_tree/gen/almost_line.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
#include "random.h"

#include <iostream>
#include <tuple>
#include <vector>

#include "../params.h"

using namespace std;

template <class T, class S>
inline bool chmax(T& a, const S& b) {
return (a < b ? a = b, 1 : 0);
}
template <class T, class S>
inline bool chmin(T& a, const S& b) {
return (a > b ? a = b, 1 : 0);
}

template <class T>
using vc = vector<T>;

template <typename T>
struct Edge {
int frm, to;
T cost;
int id;
};

template <typename T = int, bool directed = false>
struct Graph {
int N, M;
using cost_type = T;
using edge_type = Edge<T>;
vector<edge_type> edges;
vector<int> indptr;
vector<edge_type> csr_edges;
bool prepared;

class OutgoingEdges {
public:
OutgoingEdges(const Graph* G, int l, int r) : G(G), l(l), r(r) {}

const edge_type* begin() const {
if (l == r) { return 0; }
return &G->csr_edges[l];
}

const edge_type* end() const {
if (l == r) { return 0; }
return &G->csr_edges[r];
}

private:
const Graph* G;
int l, r;
};

bool is_prepared() { return prepared; }
constexpr bool is_directed() { return directed; }

Graph() : N(0), M(0), prepared(0) {}
Graph(int N) : N(N), M(0), prepared(0) {}

void build() {
assert(!prepared);
prepared = true;
indptr.assign(N + 1, 0);
for (auto&& e: edges) {
indptr[e.frm + 1]++;
if (!directed) indptr[e.to + 1]++;
}
for (int v = 0; v < N; ++v) { indptr[v + 1] += indptr[v]; }
auto counter = indptr;
csr_edges.resize(indptr.back() + 1);
for (auto&& e: edges) {
csr_edges[counter[e.frm]++] = e;
if (!directed) csr_edges[counter[e.to]++] = edge_type({e.to, e.frm, e.cost, e.id});
}
}

void add(int frm, int to, T cost = 1, int i = -1) {
assert(!prepared);
assert(0 <= frm && 0 <= to && to < N);
if (i == -1) i = M;
auto e = edge_type({frm, to, cost, i});
edges.emplace_back(e);
++M;
}
OutgoingEdges operator[](int v) const {
assert(prepared);
return {this, indptr[v], indptr[v + 1]};
}
};

template <typename Graph>
struct HLD {
Graph& G;
using Graph_type = Graph;
using WT = typename Graph::cost_type;
int N;
vector<int> LID, RID, head, V, parent, root;
vc<int> depth;
vc<WT> depth_weighted;
vector<bool> in_tree;

HLD(Graph& G, int r = -1)
: G(G), N(G.N), LID(G.N), RID(G.N), head(G.N, r), V(G.N), parent(G.N, -1), root(G.N, -1), depth(G.N, -1), depth_weighted(G.N, 0), in_tree(G.M, 0) {
assert(G.is_prepared());
int t1 = 0;
if (r != -1) {
dfs_sz(r, -1);
dfs_hld(r, t1);
} else {
for (int r = 0; r < N; ++r) {
if (parent[r] == -1) {
head[r] = r;
dfs_sz(r, -1);
dfs_hld(r, t1);
}
}
}
for (auto&& v: V) root[v] = (parent[v] == -1 ? v : root[parent[v]]);
}

void dfs_sz(int v, int p) {
auto& sz = RID;
parent[v] = p;
depth[v] = (p == -1 ? 0 : depth[p] + 1);
sz[v] = 1;
int l = G.indptr[v], r = G.indptr[v + 1];
auto& csr = G.csr_edges;
// 使う辺があれば先頭にする
for (int i = r - 2; i >= l; --i) {
if (depth[csr[i + 1].to] == -1) swap(csr[i], csr[i + 1]);
}
int hld_sz = 0;
for (int i = l; i < r; ++i) {
auto e = csr[i];
if (depth[e.to] != -1) continue;
in_tree[e.id] = 1;
depth_weighted[e.to] = depth_weighted[v] + e.cost;
dfs_sz(e.to, v);
sz[v] += sz[e.to];
if (chmax(hld_sz, sz[e.to]) && l < i) { swap(csr[l], csr[i]); }
}
}

void dfs_hld(int v, int& times) {
LID[v] = times++;
RID[v] += LID[v];
V[LID[v]] = v;
bool heavy = true;
for (auto&& e: G[v]) {
if (!in_tree[e.id] || depth[e.to] <= depth[v]) continue;
head[e.to] = (heavy ? head[v] : e.to);
heavy = false;
dfs_hld(e.to, times);
}
}

/* k: 0-indexed */
int LA(int v, int k) {
assert(k <= depth[v]);
while (1) {
int u = head[v];
if (LID[v] - k >= LID[u]) return V[LID[v] - k];
k -= LID[v] - LID[u] + 1;
v = parent[u];
}
}

int LCA(int u, int v) {
for (;; v = parent[head[v]]) {
if (LID[u] > LID[v]) swap(u, v);
if (head[u] == head[v]) return u;
}
}

int lca(int u, int v) { return LCA(u, v); }
int la(int u, int v) { return LA(u, v); }

int subtree_size(int v) { return RID[v] - LID[v]; }

int dist(int a, int b) {
int c = LCA(a, b);
return depth[a] + depth[b] - 2 * depth[c];
}
};

int main(int, char* argv[]) {
long long seed = atoll(argv[1]);
auto gen = Random(seed);

int n = N_MAX;
int q = Q_MAX;

// vertex add path sum から
vector<int> u(n - 1), v(n - 1);
for (int i = 0; i < n - (n / 2); i++) {
u[i] = i;
v[i] = i + 1;
}
for (int i = n - (n / 2); i < n - 1; i++) {
u[i] = gen.uniform(0, i);
v[i] = i + 1;
}

vector<int> new_idx(n);
for (int i = 0; i < n; ++i) { new_idx[i] = i; }
gen.shuffle(new_idx.begin(), new_idx.end());
for (int i = 0; i < n - 1; ++i) u[i] = new_idx[u[i]];
for (int i = 0; i < n - 1; ++i) v[i] = new_idx[v[i]];

// ここから他の gen に合流
int N = n, Q = q;
using edge = std::pair<int, int>;
std::vector<edge> edges;
for (int i = 0; i < N - 1; i++) { edges.emplace_back(u[i], v[i]); }
gen.shuffle(edges.begin(), edges.end());

Graph<int, 0> G(N);
printf("%d %d\n", N, Q);
for (auto e: edges) {
int u, v;
std::tie(u, v) = e;
printf("%d %d\n", u, v);
G.add(u, v);
}
G.build();
HLD<decltype(G)> hld(G);

for (int q = 0; q < Q; ++q) {
int s = gen.uniform<int>(0, N - 1);
int t = gen.uniform<int>(0, N - 1);
int dst = hld.dist(s, t);
int i;
if (gen.uniform<int>(0, 9) == 0) {
i = gen.uniform<int>(0, N - 1);
} else {
i = gen.uniform<int>(0, dst);
}
printf("%d %d %d\n", s, t, i);
}

return 0;
}
8 changes: 8 additions & 0 deletions tree/jump_on_tree/hash.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
{
"almost_line_00.in": "31fed8be580b7d84b56e701f6fa5fe64408e43ff05b8a9abe46f22d1f23ce992",
"almost_line_00.out": "f30575861f673e7d9482d3f96f61a0c8add0e0912cfe0fa54a2e790f4c696df9",
"almost_line_01.in": "029b57016635ae0bb4f2a60ada1f9a2a92c16ab68e4102323c6916ade7615747",
"almost_line_01.out": "37582c004ce62c5e76f71e29e597617e83a1cc818ffd556243f071342ede1dd4",
"almost_line_02.in": "0f1cbf3a9425bf5a5872f10dfe150352a53f3e3eb218276274ebb6018778b872",
"almost_line_02.out": "a8c64792242c739e7adb2973987d089caf36a3af1e7be188b1bf203aac49ac62",
"almost_line_03.in": "4ea0b2ee192b17c6b58fa72103afe19cb2141df9d2cfa65a5650655ee1bf259e",
"almost_line_03.out": "43042a2281f2ba0551580b8ca83d3c8ef83b1b0897ee60c44c3eaa37bee653e8",
"almost_uni_00.in": "c9af905806b10704f09635ef03bfd43be0f11970066a9906a7fdf4cf76330061",
"almost_uni_00.out": "950c56169933930630d754ad94473171c18b92df1913abe76be8de4274f571ed",
"almost_uni_01.in": "32e60e03378c884bffb07ed38ff2e1d71ddeb56fca1605c53b082df501eba278",
Expand Down
4 changes: 4 additions & 0 deletions tree/jump_on_tree/info.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ forum = "https://github.com/yosupo06/library-checker-problems/issues/809"
name = "almost_uni.cpp"
number = 2

[[tests]]
name = "almost_line.cpp"
number = 4

[[tests]]
name = "line.cpp"
number = 1
Expand Down

0 comments on commit be0862b

Please sign in to comment.