This documentation is automatically generated by online-judge-tools/verification-helper
#include "Graph/contour.hpp"
#pragma once
#include "Graph/centroid.hpp"
#include "Graph/hld.hpp"
struct ContourQuery {
using P = pair<int, int>;
using T = pair<int, P>;
ContourQuery(int _n = 0)
: n(_n), m(_n), cd(_n), hld(_n), tree(_n * 3), depth(_n * 3),
base(_n * 3), parent(_n * 3, -1), buf(_n * 3), width(_n * 3, 1),
seg(_n * 3) {}
void add_edge(int u, int v) {
cd.add_edge(u, v);
hld.add_edge(u, v);
}
vector<int> run() {
hld.run();
root = rec(0);
depth[0] = 0;
dfs(0, -1);
rep(v, 0, m) if (v != root) {
seg[v] = width[v];
}
return seg;
}
vector<P> point(int v) {
vector<P> ret;
int cur = v;
while (cur != root) {
int D =
depth[v] + depth[base[cur]] - 2 * depth[hld.lca(v, base[cur])];
ret.push_back({cur, D});
cur = parent[cur];
}
return ret;
}
vector<T> range(int v, int L, int R) {
vector<T> ret;
if (L <= 0 and 0 < R)
ret.push_back({v, {0, 1}});
int cur = parent[v], pre = v;
while (pre != root) {
int bro = -1;
for (auto &to : tree[cur])
if (to != parent[cur] and to != pre) {
bro = to;
break;
}
if (bro != -1) {
int D = depth[v] + depth[base[bro]] -
2 * depth[hld.lca(v, base[bro])];
ret.push_back(
{bro,
{clamp(L - D, 0, seg[bro]), clamp(R - D, 0, seg[bro])}});
}
pre = cur;
cur = parent[cur];
}
return ret;
}
private:
int n, m, root;
CentroidDecomposition cd;
HLD hld;
vector<vector<int>> tree;
vector<int> depth, base, parent, buf, width, seg;
int rec(int rt) {
int cen = cd.find(rt);
cd.used[cen] = 1;
buf[cen] = 1;
queue<P> que;
auto cmp = [&](int u, int v) { return buf[u] > buf[v]; };
priority_queue<int, vector<int>, decltype(cmp)> pq{cmp};
pq.push(cen);
depth[cen] = 0;
base[cen] = cen;
for (auto &to : cd.g[cen])
if (!cd.used[to]) {
int v = rec(to);
que.push({to, cen});
depth[to] = 1;
while (!que.empty()) {
auto [cur, par] = que.front();
que.pop();
width[v] = depth[cur] + 1;
for (auto &nxt : cd.g[cur])
if (nxt != par and !cd.used[nxt]) {
depth[nxt] = depth[cur] + 1;
que.push({nxt, cur});
}
}
pq.push(v);
base[v] = cen;
}
cd.used[cen] = 0;
if (pq.size() > 1) {
for (;;) {
int v1 = pq.top();
pq.pop();
int v2 = pq.top();
pq.pop();
int extra = m++;
tree[extra].push_back(v1);
tree[extra].push_back(v2);
tree[v1].push_back(extra);
tree[v2].push_back(extra);
buf[extra] = buf[v1] + buf[v2];
parent[v1] = parent[v2] = extra;
if (pq.empty()) {
return extra;
}
pq.push(extra);
base[extra] = cen;
width[extra] = max(width[v1], width[v2]);
}
} else {
int extra = m++;
tree[extra].push_back(cen);
tree[cen].push_back(extra);
buf[extra] = 1;
parent[cen] = extra;
return extra;
}
}
void dfs(int v, int p) {
for (auto &to : cd.g[v])
if (to != p) {
depth[to] = depth[v] + 1;
dfs(to, v);
}
}
};
/**
* @brief Contour Sum Query
*/
#line 2 "Graph/centroid.hpp"
class CentroidDecomposition {
void get(int v, int p) {
sz[v] = 1;
for (auto &to : g[v])
if (to != p and !used[to]) {
get(to, v);
sz[v] += sz[to];
}
}
int dfs(int v, int p, int rt) {
for (auto &to : g[v])
if (to != p and !used[to]) {
if (sz[to] > (sz[rt] >> 1))
return dfs(to, v, rt);
}
return v;
}
public:
int n, all;
vector<vector<int>> g;
vector<int> sz, used;
CentroidDecomposition(int n_) : n(n_), g(n), sz(n), used(n) {}
void add_edge(int u, int v) {
g[u].push_back(v);
g[v].push_back(u);
}
int size(int rt) {
get(rt, -1);
return sz[rt];
}
int find(int rt) {
get(rt, -1);
all = sz[rt];
int res = dfs(rt, -1, rt);
return res;
}
};
/**
* @brief Centroid Decomposition
*/
#line 2 "Graph/hld.hpp"
struct HLD{
using P=pair<int,int>;
vector<vector<int>> g; vector<int> sz,in,out,rev,hs,par,dist;
void dfs(int v,int p){
par[v]=p; sz[v]=1;
if(p!=-1)dist[v]=dist[p]+1;
if(!g[v].empty() and g[v][0]==p)swap(g[v][0],g[v].back());
for(auto& to:g[v])if(to!=p){
dfs(to,v); sz[v]+=sz[to];
if(sz[g[v][0]]<sz[to])swap(g[v][0],to);
}
}
void dfs2(int v,int p,int& k){
in[v]=k++; rev[in[v]]=v;
for(auto& to:g[v])if(to!=p){
hs[to]=(g[v][0]==to?hs[v]:to);
dfs2(to,v,k);
}
out[v]=k;
}
HLD(int _n):g(_n),sz(_n),in(_n),out(_n),rev(_n),hs(_n),par(_n),dist(_n){}
void add_edge(int u,int v){
g[u].emplace_back(v); g[v].emplace_back(u);
}
void run(int rt=0){dfs(rt,-1); hs[rt]=rt; int k=0; dfs2(rt,-1,k);}
int lca(int u,int v){
for(;;v=par[hs[v]]){
if(in[u]>in[v])swap(u,v);
if(hs[u]==hs[v])return u;
}
}
vector<P> get(int u,int p,bool es=0){
assert(in[p]<=in[u] and out[u]<=out[p]);
vector<P> res;
while(hs[u]!=hs[p]){
res.push_back({in[hs[u]],in[u]+1});
u=par[hs[u]];
}
res.push_back({in[p]+es,in[u]+1});
return res;
}
int jump(int u,int v,int k){
if(k<0)return -1;
int g=lca(u,v);
int d0=dist[u]+dist[v]-dist[g]*2;
if(d0<k)return -1;
int st=u;
if(dist[u]-dist[g]<k)st=v,k=d0-k;
for(;;){
int to=hs[st];
if(in[st]-k>=in[to])return rev[in[st]-k];
k-=in[st]-in[to]+1; st=par[to];
}
}
};
/**
* @brief Heavy Light Decomposition
*/
#line 4 "Graph/contour.hpp"
struct ContourQuery {
using P = pair<int, int>;
using T = pair<int, P>;
ContourQuery(int _n = 0)
: n(_n), m(_n), cd(_n), hld(_n), tree(_n * 3), depth(_n * 3),
base(_n * 3), parent(_n * 3, -1), buf(_n * 3), width(_n * 3, 1),
seg(_n * 3) {}
void add_edge(int u, int v) {
cd.add_edge(u, v);
hld.add_edge(u, v);
}
vector<int> run() {
hld.run();
root = rec(0);
depth[0] = 0;
dfs(0, -1);
rep(v, 0, m) if (v != root) {
seg[v] = width[v];
}
return seg;
}
vector<P> point(int v) {
vector<P> ret;
int cur = v;
while (cur != root) {
int D =
depth[v] + depth[base[cur]] - 2 * depth[hld.lca(v, base[cur])];
ret.push_back({cur, D});
cur = parent[cur];
}
return ret;
}
vector<T> range(int v, int L, int R) {
vector<T> ret;
if (L <= 0 and 0 < R)
ret.push_back({v, {0, 1}});
int cur = parent[v], pre = v;
while (pre != root) {
int bro = -1;
for (auto &to : tree[cur])
if (to != parent[cur] and to != pre) {
bro = to;
break;
}
if (bro != -1) {
int D = depth[v] + depth[base[bro]] -
2 * depth[hld.lca(v, base[bro])];
ret.push_back(
{bro,
{clamp(L - D, 0, seg[bro]), clamp(R - D, 0, seg[bro])}});
}
pre = cur;
cur = parent[cur];
}
return ret;
}
private:
int n, m, root;
CentroidDecomposition cd;
HLD hld;
vector<vector<int>> tree;
vector<int> depth, base, parent, buf, width, seg;
int rec(int rt) {
int cen = cd.find(rt);
cd.used[cen] = 1;
buf[cen] = 1;
queue<P> que;
auto cmp = [&](int u, int v) { return buf[u] > buf[v]; };
priority_queue<int, vector<int>, decltype(cmp)> pq{cmp};
pq.push(cen);
depth[cen] = 0;
base[cen] = cen;
for (auto &to : cd.g[cen])
if (!cd.used[to]) {
int v = rec(to);
que.push({to, cen});
depth[to] = 1;
while (!que.empty()) {
auto [cur, par] = que.front();
que.pop();
width[v] = depth[cur] + 1;
for (auto &nxt : cd.g[cur])
if (nxt != par and !cd.used[nxt]) {
depth[nxt] = depth[cur] + 1;
que.push({nxt, cur});
}
}
pq.push(v);
base[v] = cen;
}
cd.used[cen] = 0;
if (pq.size() > 1) {
for (;;) {
int v1 = pq.top();
pq.pop();
int v2 = pq.top();
pq.pop();
int extra = m++;
tree[extra].push_back(v1);
tree[extra].push_back(v2);
tree[v1].push_back(extra);
tree[v2].push_back(extra);
buf[extra] = buf[v1] + buf[v2];
parent[v1] = parent[v2] = extra;
if (pq.empty()) {
return extra;
}
pq.push(extra);
base[extra] = cen;
width[extra] = max(width[v1], width[v2]);
}
} else {
int extra = m++;
tree[extra].push_back(cen);
tree[cen].push_back(extra);
buf[extra] = 1;
parent[cen] = extra;
return extra;
}
}
void dfs(int v, int p) {
for (auto &to : cd.g[v])
if (to != p) {
depth[to] = depth[v] + 1;
dfs(to, v);
}
}
};
/**
* @brief Contour Sum Query
*/