Peaks BZOJ 3545 / Peaks加强版 BZOJ 3551
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,表示一组询问。
【输出格式】
对于每组询问,输出一个整数表示答案。
【样例输入】
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重构树
即对于每一次连边,我们新建一个节点p,将两点祖先的父亲设为p,并将边权附为p的点权
那么就有这个树上就有许多性质:
1.树是二叉树
2.点权是大根堆的结构
3.新树中两点路径点权的信息(最大值、最小值)和原树中两点路径边权的信息相等
那么根据2、3,原树中两点路径上最大的边权就是新树中两点的最近公共祖先的点权
那么处理出Dfs序,就可以用主席树维护区间第k大值(需要离散)
1 #include<cmath>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<iostream>
6 #include<algorithm>
7 using namespace std;
8 const int inf = 2147483647;
9 const int logp = 18;
10 const int maxn = 1e5 + 233;
11 const int maxm = 5e5 + 233;
12 const int maxp = maxn << 1;
13 const int maxe = maxp << 1;
14 const int maxs = maxp * logp ;
15 int n, m, q, p;
16 int num, cnt, tot;
17 int d[maxn], h[maxn];
18 int fat[maxp], val[maxp];
19 int rt[maxp], lc[maxs], rc[maxs], sum[maxs];
20 int si[maxp], dep[maxp], dfn[maxp], pos[maxp];
21 int fir[maxp], nex[maxe], ver[maxe];
22 int fa[logp + 1][maxp];
23 int pr[logp + 1], lg[maxp];
24 struct edge
25 {
26 int x, y, z;
27 };
28 edge a[maxm];
29 inline bool rule(edge a, edge b)
30 {
31 return a.z < b.z;
32 }
33 inline void Scan(int &x)
34 {
35 char c;
36 bool o = false;
37 while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
38 x = c - '0';
39 while(isdigit(c = getchar())) x = x * 10 + c - '0';
40 if(o) x = -x;
41 }
42 inline void Disc()
43 {
44 sort(d + 1, d + 1 + n);
45 for(int i = 1; i <= n; ++i) h[i] = lower_bound(d + 1, d + 1 + n, h[i]) - d;
46 }
47 inline int Find(int x)
48 {
49 return (fat[x] != x) ? fat[x] = Find(fat[x]) : x;
50 }
51 inline void Ins(int x, int y)
52 {
53 nex[++tot] = fir[x];
54 fir[x] = tot;
55 ver[tot] = y;
56 }
57 void Dfs(int u)
58 {
59 si[u] = 1;
60 dfn[u] = ++num;
61 pos[num] = u;
62 for(int i = fir[u]; i; i = nex[i])
63 {
64 int v = ver[i];
65 fa[0][v] = u;
66 dep[v] = dep[u] + 1;
67 Dfs(v);
68 si[u] += si[v];
69 }
70 }
71 inline void Kruskal()
72 {
73 p = n;
74 sort(a + 1, a + 1 + m, rule);
75 for(int i = 1; i <= m; ++i)
76 {
77 int x = Find(a[i].x), y = Find(a[i].y);
78 if(x != y)
79 {
80 fat[++p] = p;
81 val[p] = a[i].z;
82 fat[x] = fat[y] = p;
83 Ins(p, x), Ins(p, y);
84 if(p == (n << 1) - 1) break;
85 }
86 }
87 }
88 inline void Erg()
89 {
90 num = 0;
91 for(int i = 1; i <= p; ++i)
92 if(!dfn[i])
93 Dfs(Find(i));
94 }
95 inline void Table()
96 {
97 pr[0] = 1;
98 for(int i = 1; i <= logp; ++i)
99 {
100 pr[i] = pr[i - 1] << 1;
101 if(pr[i] > p) break;
102 lg[pr[i]] = 1;
103 }
104 for(int i = 1; i <= p; ++i) lg[i] += lg[i - 1];
105 }
106 inline void Rmq()
107 {
108 for(int k = 1; k <= lg[p]; ++k)
109 for(int i = 1; i <= p; ++i)
110 {
111 if(dep[i] < pr[k]) continue;
112 fa[k][i] = fa[k - 1][fa[k - 1][i]];
113 }
114 }
115 int Add(int p, int l, int r, int x)
116 {
117 int k = ++cnt;
118 sum[k] = sum[p] + 1;
119 if(l == r) return k;
120 int mi = l + r >> 1;
121 if(x <= mi) lc[k] = Add(lc[p], l, mi, x), rc[k] = rc[p];
122 else rc[k] = Add(rc[p], mi + 1, r, x), lc[k] = lc[p];
123 return k;
124 }
125 inline void Build()
126 {
127 Kruskal();
128 Erg();
129 Table();
130 Rmq();
131 for(int i = 1; i <= num; ++i)
132 {
133 int x = pos[i];
134 if(x > n) rt[i] = rt[i - 1];
135 else rt[i] = Add(rt[i - 1], 1, n, h[x]);
136 }
137 }
138 inline int Jump(int x, int v)
139 {
140 int len = lg[dep[x]];
141 for(int i = len; i >= 0; --i)
142 if(val[fa[i][x]] <= v)
143 x = fa[i][x];
144 return x;
145 }
146 int Query(int a, int b, int l, int r, int k)
147 {
148 if(l == r) return l;
149 int amo = sum[rc[b]] - sum[rc[a]];
150 int mi = l + r >> 1;
151 if(amo < k) return Query(lc[a], lc[b], l, mi, k - amo);
152 return Query(rc[a], rc[b], mi + 1, r, k);
153 }
154 int Ask(int x, int v, int k)
155 {
156 int anc = Jump(x, v);
157 int beg = rt[dfn[anc] - 1];
158 int end = rt[dfn[anc] + si[anc] - 1];
159 if(sum[end] - sum[beg] < k) return -1;
160 int hi = Query(beg, end, 1, n, k);
161 return d[hi];
162 }
163 int main()
164 {
165 Scan(n), Scan(m), Scan(q);
166 val[0] = inf;
167 for(int i = 1; i <= n; ++i) Scan(h[i]), d[i] = h[i], fat[i] = i;
168 Disc();
169 for(int i = 1; i <= m; ++i) Scan(a[i].x), Scan(a[i].y), Scan(a[i].z);
170 Build();
171 int ans = -1;
172 while(q--)
173 {
174 int x, v, k;
175 Scan(x), Scan(v), Scan(k);
176 if(ans != -1) x ^= ans, v ^= ans, k ^= ans;
177 ans = Ask(x, v, k);
178 printf("%d\n", ans);
179 }
180 }