码迷,mamicode.com
首页 > 其他好文 > 详细

P4197 Peaks

时间:2019-01-03 19:26:49      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:一个   roo   col   题目   bool   mount   输入   lin   倍增   

\(\color{#0066ff}{题目描述}\)

在Bytemountains有N座山峰,每座山峰有他的高度\(h_i\) 。有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个困难值,这个值越大表示越难走,现在有\(Q\)组询问,每组询问询问从点\(v\)开始只经过困难值小于等于\(x\)的路径所能到达的山峰中第\(k\)高的山峰,如果无解输出\(-1\)

\(\color{#0066ff}{输入格式}\)

第一行三个数\(N,M,Q\)。 第二行\(N\)个数,第i个数为\(h_i\) 接下来\(M\)行,每行\(3\)个数\(a,b,c\),表示从\(a\)\(b\)有一条困难值为\(c\)的双向路径。 接下来\(Q\)行,每行三个数\(v,x,k\) 表示一组询问。

\(\color{#0066ff}{输出格式}\)

对于每组询问,输出一个整数表示答案。

\(\color{#0066ff}{输入样例}\)

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

\(\color{#0066ff}{输出样例}\)

6
1
-1
8

\(\color{#0066ff}{数据范围与提示}\)

\(N \leq 10^5, 0 \leq M, Q \leq 5 * 10^5, h_i, c, x \leq 10^9\)

\(\color{#0066ff}{题解}\)

Kruskal重构树

以困难程度为关键字建立大根堆

倍增找到最浅点

对于子树内的叶子,就是能到的所有点

找到这些点的第k大

考虑dfs序

只记录叶子节点的dfs序

同一子树内dfs序连续

用主席树维护就行了

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; int x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int maxn = 8e5 + 100;
struct tree {
protected:
    struct node {
        int num;
        node *ch[2];
        node(int num = 0): num(num) {
            ch[0] = ch[1] = NULL;
        }
        void *operator new (size_t) {
            static node *S = NULL, *T = NULL;
            return (S == T) && (T = (S = new node[1024]) + 1024), S++;
        }
    };
    node *root[maxn];
    void ins(node *&o, node *ls, int l, int r, int val) {
        o = new node();
        *o = *ls;
        o->num++;
        if(l == r) return;
        int mid = (l + r) >> 1;
        if(val <= mid) ins(o->ch[0], ls->ch[0], l, mid, val);
        else ins(o->ch[1], ls->ch[1], mid + 1, r, val);
    }
    int query(node *x, node *y, int l, int r, int k) {
        if(l == r) return l;
        int siz = y->ch[0]->num - x->ch[0]->num;
        int mid = (l + r) >> 1;
        if(k <= siz) return query(x->ch[0], y->ch[0], l, mid, k);
        else return query(x->ch[1], y->ch[1], mid + 1, r, k - siz);
    }
    void init() {
        root[0] = new node();
        root[0]->ch[0] = root[0]->ch[1] = root[0];
    }
public:
    tree() { init(); }
    void ins(int *s, int *t, int *m, int n, int len) {
        for(int i = 1; i <= n; i++) ins(root[i], root[i - 1], 1, len, std::lower_bound(t + 1, t + len + 1, s[m[i]]) - t);
    }
    int query(int l, int r, int k, int len) { return query(root[l - 1], root[r], 1, len, k); }
};
int n, m, q;
struct E {
    int x, y, z;
    bool operator < (const E &b) const {
        return z < b.z;
    }
}e[maxn];
struct node {
    int to;
    node *nxt;
    node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
    void *operator new (size_t) {
        static node *S = NULL, *T = NULL;
        return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    }
};
node *head[maxn];
tree s;
int h[maxn], l[maxn], r[maxn], fa[maxn], hh[maxn], len = 1;
int findset(int x) { return x == fa[x]? fa[x] : fa[x] = findset(fa[x]); }
int f[maxn][26], dfn, redfn[maxn];
void add(int from, int to) {
    head[from] = new node(to, head[from]);
}
void dfs(int x, int ff) {
    f[x][0] = ff;
    if(x <= n) redfn[++dfn] = x;
    else l[x] = dfn + 1;
    for(node *i = head[x]; i; i = i->nxt) 
        if(i->to != ff) dfs(i->to, x);
    if(x > n) r[x] = dfn;
}
int query(int v, int x, int k) {
    for(int i = 24; i >= 0; i--) if(f[v][i] && h[f[v][i]] <= x) v = f[v][i];
    if(r[v] - l[v] + 1 < k) return -1;
    return hh[s.query(l[v], r[v], r[v] - l[v] + 2 - k, len)];
}
int main() {
    n = in(), m = in(), q = in();
    for(int i = 1; i <= n; i++) hh[i] = h[i] = in(), fa[i] = i;
    for(int i = 1; i <= m; i++) e[i].x = in(), e[i].y = in(), e[i].z = in();
    std::sort(hh + 1, hh + n + 1);
    std::sort(e + 1, e + m + 1);
    for(int i = 2; i <= n; i++) if(hh[i] != hh[i - 1]) hh[++len] = hh[i];
    int cnt = n, tot = 0;
    for(int i = 1; i <= m; i++) {
        int x = findset(e[i].x);
        int y = findset(e[i].y);
        if(x != y) {
            fa[x] = fa[y] = ++cnt;
            fa[cnt] = cnt;
            h[cnt] = e[i].z;
            add(cnt, x), add(cnt, y);
            tot++;
        }
        if(tot == n - 1) break;
    }
    dfs(cnt, 0);
    for(int j = 1; j <= 24; j++)
        for(int i = 1; i <= cnt; i++) 
            f[i][j] = f[f[i][j - 1]][j - 1];
    s.ins(h, hh, redfn, n, len);
    int v, x, k;
    while(q --> 0) {
        v = in(), x = in(), k = in();
        printf("%d\n", query(v, x, k));
    }
    return 0;
}

P4197 Peaks

标签:一个   roo   col   题目   bool   mount   输入   lin   倍增   

原文地址:https://www.cnblogs.com/olinr/p/10215947.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!