luogu P4197 Peaks
嘟嘟嘟
今天刷了一下NOI2018Day1的题,T1不会kruskal重构树就敲了60分暴力。
于是特意找了一条kruskal重构树板子刷一下。
这东西不难,感觉还挺有意思的。
这篇博客简明易懂:Kruskal重构树—学习笔记。
对于这道题,我们建完重构树后,对于每一个询问,倍增向上跳到小于等于\(x\)且权值最大的点,然后就是查询这个点的子树内第\(k\)大的叶子节点的权值了。
因为一个子树内的dfs序是连续的,所以可以用主席树解决。dfs的时候继承节点\(u\)dfs序前一个的点。然后只有到叶子节点的时候再插入,其余情况直接继承树根。
对了,如果图不连通,那么就是一个森林了,得从每一个树根分别dfs。但这题的图似乎是连通的。
还有,这题没说清楚,应该是第\(k\)大的节点的权值,不是编号。恰巧样例里每一个点的权值和编号还是一样的,特别坑。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
const int maxm = 5e5 + 5;
const int maxN = 5e6 + 5;
const int N = 18;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m, q, ncnt;
int a[maxn], T[maxn], _n;
struct Node
{
int x, y, w;
In bool operator < (const Node& oth)const
{
return w < oth.w;
}
}t[maxm];
struct Edge
{
int nxt, to;
}e[maxn];
int head[maxn], ecnt = -1;
In void addEdge(int x, int y)
{
e[++ecnt] = (Edge){head[x], y};
head[x] = ecnt;
}
int p[maxn];
In int Find(int x) {return x == p[x] ? x : p[x] = Find(p[x]);}
int root[maxn];
int ls[maxN], rs[maxN], sum[maxN], tcnt;
In void insert(int old, int& now, int l, int r, int id, int pos)
{
now = ++tcnt;
ls[now] = ls[old], rs[now] = rs[old];
sum[now] = sum[old] + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(id <= mid) insert(ls[old], ls[now], l, mid, id, pos);
else insert(rs[old], rs[now], mid + 1, r, id, pos);
}
In int query(int old, int now, int l, int r, int k)
{
if(sum[now] < k) return -1;
if(l == r) return l;
int mid = (l + r) >> 1, Sum = sum[rs[now]] - sum[rs[old]];
if(k <= Sum) return query(rs[old], rs[now], mid + 1, r, k);
else return query(ls[old], ls[now], l, mid, k - Sum);
}
int dep[maxn], siz[maxn], dfsx[maxn], cnt = 0;
int fa[N + 2][maxn], Max[N + 2][maxn];
In void dfs(int now)
{
dfsx[now] = ++cnt; siz[now] = 1;
if(now <= n) insert(root[dfsx[now] - 1], root[dfsx[now]], 1, _n, a[now], now);
else root[dfsx[now]] = root[dfsx[now] - 1];
for(int i = 1; (1 << i) <= dep[now]; ++i)
{
fa[i][now] = fa[i - 1][fa[i - 1][now]];
Max[i][now] = max(Max[i - 1][now], Max[i - 1][fa[i - 1][now]]);
}
for(int i = head[now], v; ~i; i = e[i].nxt)
{
dep[v = e[i].to] = dep[now] + 1;
fa[0][v] = now, Max[0][v] = a[now];
dfs(v);
siz[now] += siz[v];
}
}
In int solve(int x, int d)
{
for(int i = N; i >= 0; --i)
if(fa[i][x] && Max[i][x] <= d) x = fa[i][x];
return x;
}
int main()
{
//freopen("ha.in", "r", stdin);
//freopen("ha.out", "w", stdout);
Mem(head, -1);
n = read(), m = read(), q = read();
for(int i = 1; i <= n; ++i) a[i] = read(), p[i] = i;
for(int i = 1; i <= m; ++i) t[i].x = read(), t[i].y = read(), t[i].w = read();
sort(t + 1, t + m + 1);
ncnt = n;
for(int i = 1; i <= m; ++i)
{
int x = t[i].x, y = t[i].y;
int px = Find(x), py = Find(y);
if(px == py) continue;
a[++ncnt] = t[i].w; p[ncnt] = ncnt;
addEdge(ncnt, px), addEdge(ncnt, py);
p[px] = ncnt, p[py] = ncnt;
}
for(int i = 1; i <= n; ++i) T[i] = a[i];
sort(T + 1, T + n + 1);
_n = unique(T + 1, T + n + 1) - T - 1;
for(int i = 1; i <= n; ++i)
a[i] = lower_bound(T + 1, T + _n + 1, a[i]) - T;
dfs(ncnt);
for(int i = 1; i <= q; ++i)
{
int v = read(), x = read(), K = read();
v = solve(v, x);
int ans = query(root[dfsx[v] - 1], root[dfsx[v] + siz[v] - 1], 1, _n, K);
write(ans == -1 ? -1 : T[ans]), enter;
}
return 0;
}