[BZOJ3551][ONTAK2010]Peaks加强版
[BZOJ3551][ONTAK2010]Peaks加强版
试题描述
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
输入
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1则不变。
输出
对于每组询问,输出一个整数表示答案。
输入示例
10 11 4 1 2 3 4 5 6 7 8 9 10 1 4 4 2 5 3 9 8 2 7 8 10 7 1 4 6 7 1 6 4 8 2 1 5 10 8 10 3 4 7 3 4 6 1 5 2 1 5 6 1 5 8 8 9 2
输出示例
6 1 -1 8
数据规模及约定
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。
题解
这题需要一个新东西:Kruskal 重构树,详情请到 popoqqq 的博客去学一下。
然后就是 dfs 序 + 主席树了。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 200010 #define maxm 500010 #define maxlog 18 #define maxnode 6666666 int n; int ToT, sumv[maxnode], lc[maxnode], rc[maxnode], rt[maxn]; void update(int& y, int x, int l, int r, int p) { sumv[y = ++ToT] = sumv[x] + 1; if(l == r) return ; int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x]; if(p <= mid) update(lc[y], lc[x], l, mid, p); else update(rc[y], rc[x], mid + 1, r, p); return ; } struct Edge { int a, b, c; Edge() {} Edge(int _1, int _2, int _3): a(_1), b(_2), c(_3) {} bool operator < (const Edge& t) const { return c < t.c; } } es[maxm]; int p_ToT, fa[maxlog][maxn], ch[maxn][2], p_val[maxn], e_val[maxn], dl[maxn], dr[maxn], clo, pid[maxn]; void build(int u) { if(!u) return ; // printf("%d u: %d %d %d\n", e_val[u], u, ch[u][0], ch[u][1]); dl[u] = ++clo; pid[clo] = u; for(int i = 1; i < maxlog; i++) fa[i][u] = fa[i-1][fa[i-1][u]]; for(int i = 0; i < 2; i++) build(ch[u][i]); dr[u] = clo; return ; } int pa[maxn], id[maxn]; int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } int num[maxn]; int query(int u, int mx, int k, int id) { for(int i = maxlog - 1; i >= 0; i--) if(fa[i][u] && e_val[fa[i][u]] <= mx) u = fa[i][u]; // printf("%d %d\n", u, e_val[u]); int lrt = rt[dl[u]-1], rrt = rt[dr[u]]; int l = 1, r = n; while(l < r) { int mid = l + r >> 1; // printf("[%d, %d]: %d %d\n", mid + 1, r, sumv[rc[rrt]] - sumv[rc[lrt]], k); if((rrt && rc[rrt] ? sumv[rc[rrt]] : 0) - (lrt && rc[lrt] ? sumv[rc[lrt]] : 0) < k) { k -= sumv[rc[rrt]] - sumv[rc[lrt]]; r = mid; if(lrt) lrt = lc[lrt]; if(rrt) rrt = lc[rrt]; } else { l = mid + 1; if(lrt) lrt = rc[lrt]; if(rrt) rrt = rc[rrt]; } } int ans = sumv[rrt] - sumv[lrt] >= k ? l : -1; return ans < 0 ? ans : num[ans]; } int main() { n = read(); int m = read(), q = read(); for(int i = 1; i <= n; i++) num[i] = p_val[i] = read(), pa[i] = id[i] = i; sort(num + 1, num + n + 1); for(int i = 1; i <= n; i++) p_val[i] = lower_bound(num + 1, num + n + 1, p_val[i]) - num; for(int i = 1; i <= m; i++) { int a = read(), b = read(), c = read(); es[i] = Edge(a, b, c); } sort(es + 1, es + m + 1); p_ToT = n; for(int i = 1; i <= m; i++) { int u = findset(es[i].a), v = findset(es[i].b); if(u != v) { ch[++p_ToT][0] = id[u]; ch[p_ToT][1] = id[v]; fa[0][id[v]] = fa[0][id[u]] = p_ToT; e_val[p_ToT] = es[i].c; pa[v] = u; id[u] = p_ToT; } } build(id[findset(1)]); for(int i = 1; i <= clo; i++) if(p_val[pid[i]]) update(rt[i], rt[i-1], 1, n, p_val[pid[i]]); else rt[i] = rt[i-1]; int lst = 0; for(int i = 1; i <= q; i++) { int v = read() ^ lst, x = read() ^ lst, k = read() ^ lst; lst = query(v, x, k, i); printf("%d\n", lst); if(lst < 0) lst = 0; } return 0; }