总览:
处理当一个图只能经过边权大于(小于)某个权值的边的问题
对图做最小生成树,当合并两个点集时,建立新结点,并将联通两个点集的最小边权作为点权,将这个点作为原来两个点集的父亲
树的节点树为
2
n
−
1
2n-1
2n−1
树上的叶节点为原图的点,一个非叶节点代表原图中一个最小生成树
原图任意两个点路径上边权的最大值为它们树上的 LCA 的点权
以每个节点为起点,走边权不超过一定值的边所能到达的点集为树上某一结点的子树,dfn 连续
T1 P4768 [NOI2018]归程
思路:
先跑最短路,然后建树,节点上维护子树叶节点的
m
i
n
d
i
s
min_{dis}
mindis,查询就倍增到能到达的最浅节点,然后输出
m
i
n
d
i
s
min_{dis}
mindis
代码:
#include <bits/stdc++.h>
using namespace std;
#define re register
#define LL long long
typedef unsigned int uint;
typedef unsigned long long ull;
#define pb push_back
#define mp make_pair
namespace IO {
char _buf[1 << 21], *_p1 = _buf, *_p2 = _buf;
#define ch() \
(_p1 == _p2 && \
(_p2 = (_p1 = _buf) + fread(_buf, 1, 1 << 21, stdin), _p1 == _p2) \
? EOF \
: *_p1++)
inline int in() {
int s = 0, f = 1;
char x = ch();
for (; x < '0' || x > '9'; x = ch())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char buf_[1 << 21];
int p1_ = -1;
inline void flush() {
fwrite(buf_, 1, p1_ + 1, stdout);
p1_ = -1;
}
inline void pc(char x) {
if (p1_ == (1 << 21) - 1) flush();
buf_[++p1_] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
inline void out(string x) {
int k = x.size();
for (int i = 0; i < k; i++) pc(x[i]);
}
} // namespace IO
using namespace IO;
const int A = 5e5 + 5;
const int logA = 20;
const int INF = 1e9 + 5;
int n, m;
int dis[A], val[A];
vector<int> rt;
namespace Tree {
int head[A], tot_road;
struct Road {
int nex, to;
} road[2 * A];
inline void edge(int x, int y) {
road[++tot_road] = {head[x], y}, head[x] = tot_road;
}
int lg[A];
int dep[A], st[A][logA];
inline void DFS(int x) {
for (int i = 1; i <= lg[dep[x]]; i++) st[x][i] = st[st[x][i - 1]][i - 1];
for (int y = head[x]; y; y = road[y].nex) {
int z = road[y].to;
dep[z] = dep[x] + 1;
st[z][0] = x;
DFS(z);
dis[x] = min(dis[x], dis[z]);
}
return;
}
inline int qurey(int x, int v) {
for (int i = lg[dep[x]]; ~i; i--)
if (val[st[x][i]] > v) x = st[x][i];
return dis[x];
}
inline void work() {
lg[1] = 0;
for (int i = 2; i <= (n << 1); i++) lg[i] = lg[i >> 1] + 1;
for (int i = 0; i < rt.size(); i++) {
dep[rt[i]] = 1;
DFS(rt[i]);
}
int Q = in(), K = in(), S = in(), ans = 0;
while (Q--) {
int x = in(), y = in();
x = (x + K * ans - 1) % n + 1, y = (y + K * ans) % (S + 1);
out(ans = qurey(x, y)), pc('\n');
}
return;
}
} // namespace Tree
namespace T {
int head[A], tot_road;
struct Road {
int nex, to, w;
} road[2 * A];
inline void edge(int x, int y, int w) {
road[++tot_road] = {head[x], y, w}, head[x] = tot_road;
}
struct node {
int x, y, w;
inline friend bool operator<(node u, node v) { return u.w > v.w; }
} p[A];
int ex[A];
inline void djk() {
for (int i = 1; i <= (n << 1); i++) dis[i] = INF, ex[i] = 0;
priority_queue<pair<int, int> > q;
dis[1] = 0;
q.push(mp(-dis[1], 1));
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (ex[x]) continue;
ex[x] = 1;
for (int y = head[x]; y; y = road[y].nex) {
int z = road[y].to, w = road[y].w;
if (dis[z] > dis[x] + w) {
dis[z] = dis[x] + w;
q.push(mp(-dis[z], z));
}
}
}
return;
}
int all;
int f[A];
inline int find(int x) { return f[x] == x ? f[x] : f[x] = find(f[x]); }
inline void build() {
sort(p + 1, p + 1 + m);
all = n;
for (int i = 1; i <= (n << 1); i++) f[i] = i;
for (int i = 1; i <= m; i++) {
int x = p[i].x, y = p[i].y;
if (find(x) == find(y)) continue;
val[++all] = p[i].w;
Tree::edge(all, find(x)), Tree::edge(all, find(y));
f[find(x)] = all, f[find(y)] = all;
}
for (int i = 1; i <= all; i++)
if (find(i) == i) rt.pb(i);
return;
}
inline void work() {
n = in(), m = in();
for (int i = 1; i <= m; i++) {
int u = in(), v = in(), l = in(), a = in();
edge(u, v, l), edge(v, u, l);
p[i].x = u, p[i].y = v, p[i].w = a;
}
djk();
build();
return;
}
} // namespace T
inline void clean() {
T::tot_road = 0;
memset(T::head, 0, sizeof(T::head));
rt.clear();
Tree::tot_road = 0;
memset(Tree::head, 0, sizeof(Tree::head));
memset(Tree::st, 0, sizeof(Tree::st));
return;
}
signed main() {
int T = in();
while (T--) {
clean();
T::work();
Tree::work();
}
flush();
return 0;
}
T2 P4197 Peaks
思路:
建树后就是查询子树内第
k
k
k 高的高度
在 dfn 序上维护主席树即可
代码:
#include <bits/stdc++.h>
using namespace std;
#define re register
#define LL long long
typedef unsigned int uint;
typedef unsigned long long ull;
#define pb push_back
#define mp make_pair
namespace IO {
char _buf[1 << 21], *_p1 = _buf, *_p2 = _buf;
#define ch() \
(_p1 == _p2 && \
(_p2 = (_p1 = _buf) + fread(_buf, 1, 1 << 21, stdin), _p1 == _p2) \
? EOF \
: *_p1++)
inline int in() {
int s = 0, f = 1;
char x = ch();
for (; x < '0' || x > '9'; x = ch())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char buf_[1 << 21];
int p1_ = -1;
inline void flush() {
fwrite(buf_, 1, p1_ + 1, stdout);
p1_ = -1;
}
inline void pc(char x) {
if (p1_ == (1 << 21) - 1) flush();
buf_[++p1_] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
inline void out(string x) {
int k = x.size();
for (int i = 0; i < k; i++) pc(x[i]);
}
} // namespace IO
using namespace IO;
const int A = 5e5 + 5;
const int INF = 1e9 + 5;
const int logA = 20;
int n, m, Q;
int hi[A], val[A], all;
int ex[A];
vector<int> root;
namespace Tree {
int head[A], tot_road;
struct Road {
int nex, to;
} road[2 * A];
inline void edge(int x, int y) {
road[++tot_road] = {head[x], y}, head[x] = tot_road;
}
int lg[A], f[A][logA];
int dep[A], sz[A], pos[A], idx[A], ed[A], tot;
struct SGT {
int ls, rs;
int num;
} tr[4 * logA * A];
int rt[A], tot_;
inline void insert(int &x, int y, int l, int r, int v) {
x = ++tot_;
tr[x] = tr[y];
tr[x].num++;
if (l == r) return;
int mid = (l + r) >> 1;
if (v <= mid)
insert(tr[x].ls, tr[y].ls, l, mid, v);
else
insert(tr[x].rs, tr[y].rs, mid + 1, r, v);
return;
}
inline int Kth(int x, int y, int l, int r, int k) {
if (l == r) return l;
int mid = (l + r) >> 1;
int num = tr[tr[y].rs].num - tr[tr[x].rs].num;
if (k <= num)
return Kth(tr[x].rs, tr[y].rs, mid + 1, r, k);
else
return Kth(tr[x].ls, tr[y].ls, l, mid, k - num);
}
inline void DFS(int x) {
pos[x] = ++tot, idx[pos[x]] = x;
for (int i = 1; i <= lg[dep[x]]; i++) f[x][i] = f[f[x][i - 1]][i - 1];
for (int y = head[x]; y; y = road[y].nex) {
int z = road[y].to;
dep[z] = dep[x] + 1;
f[z][0] = x;
DFS(z);
sz[x] += sz[z];
}
if (!sz[x]) sz[x] = 1;
ed[x] = tot;
return;
}
inline int qurey(int x, int v, int k) {
for (int i = lg[dep[x]]; ~i; i--)
if (val[f[x][i]] <= v) x = f[x][i];
if (sz[x] < k) return -1;
return Kth(rt[pos[x] - 1], rt[ed[x]], 0, INF, k);
}
inline void work() {
lg[1] = 0;
for (int i = 2; i <= all; i++) lg[i] = lg[i >> 1] + 1;
for (int i = 0; i < root.size(); i++) {
dep[root[i]] = 1;
DFS(root[i]);
}
for (int i = 1; i <= tot; i++) {
rt[i] = rt[i - 1];
if (hi[idx[i]]) insert(rt[i], rt[i - 1], 0, INF, hi[idx[i]]);
}
while (Q--) {
int x = in(), v = in(), k = in();
out(qurey(x, v, k)), pc('\n');
}
return;
}
} // namespace Tree
namespace T {
struct Road {
int x, y, w;
inline friend bool operator<(Road u, Road v) { return u.w < v.w; }
} p[A];
int f[A];
inline int find(int x) { return f[x] == x ? f[x] : f[x] = find(f[x]); }
inline void work() {
n = in(), m = in(), Q = in();
for (int i = 1; i <= n; i++) hi[i] = in();
for (int i = 1; i <= m; i++) p[i].x = in(), p[i].y = in(), p[i].w = in();
sort(p + 1, p + 1 + m);
for (int i = 1; i <= (n << 1); i++) f[i] = i;
all = n;
for (int i = 1; i <= m; i++) {
int x = p[i].x, y = p[i].y;
if (find(x) == find(y)) continue;
val[++all] = p[i].w;
Tree::edge(all, find(x)), Tree::edge(all, find(y));
f[find(x)] = f[find(y)] = all;
}
val[0] = INF;
for (int i = 1; i <= n; i++)
if (!ex[find(i)]) {
root.pb(find(i));
ex[find(i)] = 1;
}
return;
}
} // namespace T
signed main() {
T::work();
Tree::work();
flush();
return 0;
}