[BZOJ3545][ONTAK2010]Peaks
Posted xjr_01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3545][ONTAK2010]Peaks相关的知识,希望对你有一定的参考价值。
[BZOJ3545][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,表示一组询问。
第二行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。
题解
考虑离线做法,我们把边和询问按权值排一遍序,然后依次处理每个询问。那么就是从小到大依次加入那些边,对于连通性,我们可以用并查集维护;对于第 k 大值,我们可以并查集里面套一个 treap;啊 treap 怎么合并?只好加一个 log 启发式合并了。
#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 100010 #define maxm 500010 struct Node { int v, r, siz; Node() {} Node(int _, int __): v(_), r(__) {} } ns[maxn]; int ToT, fa[maxn], ch[maxn][2], rec[maxn], rcnt; int getnode() { if(rcnt) { int o = rec[rcnt--]; fa[o] = ch[o][0] = ch[o][1] = 0; return o; } return ++ToT; } void maintain(int o) { ns[o].siz = 1; for(int i = 0; i < 2; i++) if(ch[o][i]) ns[o].siz += ns[ch[o][i]].siz; return ; } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(z) ch[z][ch[z][1]==y] = u; if(ch[y][1] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[u][r]] = y; ch[y][l] = ch[u][r]; ch[u][r] = y; maintain(y); maintain(u); return ; } void insert(int& o, int v) { if(!o) { ns[o = getnode()] = Node(v, rand()); return maintain(o); } bool d = v > ns[o].v; insert(ch[o][d], v); fa[ch[o][d]] = o; if(ns[ch[o][d]].r > ns[o].r) { int t = ch[o][d]; rotate(t); o = t; } return maintain(o); } int val[maxn], cntv; void recycle(int& o) { if(!o) return ; recycle(ch[o][0]); recycle(ch[o][1]); rec[++rcnt] = o; val[++cntv] = ns[o].v; fa[o] = 0; o = 0; return ; } void merge(int& u, int& v) { // printf("merge(%d, %d)\n", u, v); cntv = 0; recycle(v); // printf("vals: "); for(int i = 1; i <= cntv; i++) printf("%d%c", val[i], i < cntv ? ‘ ‘ : ‘\n‘); for(int i = 1; i <= cntv; i++) insert(u, val[i]); return ; } int Find(int o, int k) { if(!o) return -1; int rs = ch[o][1] ? ns[ch[o][1]].siz : 0; if(k == rs + 1) return ns[o].v; if(k < rs + 1) return Find(ch[o][1], k); return Find(ch[o][0], k - rs - 1); } int pa[maxn], rt[maxn]; int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); } 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]; struct Que { int u, x, k, id; Que() {} Que(int _1, int _2, int _3, int _4): u(_1), x(_2), k(_3), id(_4) {} bool operator < (const Que& t) const { return x < t.x; } } qs[maxm]; int ans[maxm]; int main() { int n = read(), m = read(), q = read(); for(int i = 1; i <= n; i++) { int v = read(); pa[i] = i; insert(rt[i], v); } 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); for(int i = 1; i <= q; i++) { int u = read(), x = read(), k = read(); qs[i] = Que(u, x, k, i); } sort(qs + 1, qs + q + 1); // for(int i = 1; i <= m; i++) printf("Edge: %d %d %d\n", es[i].a, es[i].b, es[i].c); // for(int i = 1; i <= q; i++) printf("Que: %d %d %d\n", qs[i].u, qs[i].x, qs[i].k); for(int i = 1, e = 1; i <= q; i++) { while(e <= m && es[e].c <= qs[i].x) { int u = findset(es[e].a), v = findset(es[e].b); // printf("%d: %d(%d) %d(%d) %d\n", e, u, es[e].a, v, es[e].b, findset(8)); if(u != v) { if(ns[rt[u]].siz < ns[rt[v]].siz) swap(u, v); merge(rt[u], rt[v]); pa[v] = u; } e++; } ans[qs[i].id] = Find(rt[findset(qs[i].u)], qs[i].k); } for(int i = 1; i <= q; i++) printf("%d\n", ans[i]); return 0; }
以上是关于[BZOJ3545][ONTAK2010]Peaks的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 3545ONTAK 2010Peaks & BZOJ 3551ONTAK 2010Peaks加强版 Kruskal重构树
bzoj3545[ONTAK2010]Peaks 线段树合并