[BZOJ 3551] Peaks加强版
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3551
[算法]
建出此图的kruskal重构树
用线段树合并维护每个联通块的第k大点权
这样就可以在线回答询问了
时间复杂度 : O((N + Q)log N)
[代码]
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int M = 5e5 + 10; const int MAXLOG = 17; typedef long long ll; typedef long double ld; typedef unsigned long long ull; #define rint register int struct info { int u , v , w; } a[M]; int n , m , q , tot , len , cnt; int head[N << 1] , h[N] , b[N] , fa[N << 1] , size[N << 1] , depth[N << 1] , rt[N << 1] , value[N << 1]; int father[N << 1][MAXLOG]; struct Segment_Tree { int sz; struct node { int lc , rc; int cnt; } a[N * 60]; Segment_Tree() { sz = 0; } inline void update(int now) { a[now].cnt = a[a[now].lc].cnt + a[a[now].rc].cnt; } inline void modify(int &now , int l , int r , int x , int value) { if (!now) now = ++sz; if (l == r) { a[now].cnt += value; return; } int mid = (l + r) >> 1; if (mid >= x) modify(a[now].lc , l , mid , x , value); else modify(a[now].rc , mid + 1 , r , x , value); update(now); } inline int merge(int x , int y , int l , int r) { if (x == 0 || y == 0) return x + y; int p = ++sz; a[p].cnt = a[x].cnt + a[y].cnt; int mid = (l + r) >> 1; a[p].lc = merge(a[x].lc , a[y].lc , l , mid); a[p].rc = merge(a[x].rc , a[y].rc , mid + 1 , r); return p; } inline int query(int now , int l , int r , int k) { if (l == r) return l; int mid = (l + r) >> 1; if (a[a[now].rc].cnt >= k) return query(a[now].rc , mid + 1 , r , k); else return query(a[now].lc , l , mid , k - a[a[now].rc].cnt); } } SGT; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline bool cmp(info a , info b) { return a.w < b.w; } inline int getroot(int x) { if (fa[x] == x) return x; else return fa[x] = getroot(fa[x]); } inline void kruskal() { int tot = 0; cnt = n; for (rint i = 1; i <= 2 * n; i++) fa[i] = i; for (rint i = 1; i <= m; i++) { int fu = getroot(a[i].u) , fv = getroot(a[i].v); if (fu != fv) { father[fu][0] = father[fv][0] = ++cnt; value[cnt] = a[i].w; rt[cnt] = SGT.merge(rt[fu] , rt[fv] , 1 , len); fa[fu] = fa[fv] = fa[cnt] = cnt; ++tot; } if (tot == n - 1) break; } for (int i = 1; i < MAXLOG; i++) { for (int j = 1; j <= cnt; j++) { father[j][i] = father[father[j][i - 1]][i - 1]; } } } int main() { read(n); read(m); read(q); for (rint i = 1; i <= n; i++) { read(h[i]); b[i] = h[i]; } sort(b + 1 , b + n + 1); len = unique(b + 1 , b + n + 1) - b - 1; for (rint i = 1; i <= n; i++) h[i] = lower_bound(b + 1 , b + len + 1 , h[i]) - b; for (rint i = 1; i <= n; i++) SGT.modify(rt[i] , 1 , len , h[i] , 1); for (rint i = 1; i <= m; i++) { read(a[i].u); read(a[i].v); read(a[i].w); } sort(a + 1 , a + m + 1 , cmp); kruskal(); int lastans = 0; while (q--) { int v , x , k; read(v); read(x); read(k); if (lastans != -1) { v ^= lastans; x ^= lastans; k ^= lastans; } for (rint i = MAXLOG - 1; i >= 0; i--) { if (father[v][i] && value[father[v][i]] <= x) v = father[v][i]; } if (SGT.a[rt[v]].cnt >= k) printf("%d\n" , lastans = b[SGT.query(rt[v] , 1 , len , k)]); else printf("%d\n" , lastans = -1); } return 0; }