zoukankan      html  css  js  c++  java
  • Luogu4197 Peaks

    题目链接:洛谷


    看到“只经过困难值小于等于$x$的路径”。

    感觉有点眼熟。

    ow,就是[NOI2018]归程。


    和那道题一样,可以直接建出Kruskal重构树,每次倍增寻找祖先中最上面的不大于$x$的节点$v$,$v$的子树就是可以到达的范围。

    根据Kruskal重构树的dfs序建出主席树求第$K$大。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define Rint register int
     4 using namespace std;
     5 const int N = 500003;
     6 struct Edge {
     7     int u, v, w;
     8     inline bool operator < (const Edge &o) const {return w < o.w;}
     9 } e[N];
    10 int n, m, q, _n, h[N], b[N], val[N], head[N], to[N << 1], nxt[N << 1], fa[N], tot;
    11 inline int getfa(int x){return x == fa[x] ? x : fa[x] = getfa(fa[x]);}
    12 inline void add(int a, int b){
    13     static int cnt = 0;
    14     to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
    15 }
    16 int root[N], ls[N << 5], rs[N << 5], seg[N << 5], cnt;
    17 inline void change(int &now, int pre, int L, int R, int pos){
    18     now = ++ cnt; seg[now] = seg[pre] + 1;
    19     if(L == R) return;
    20     int mid = L + R >> 1;
    21     if(pos <= mid) rs[now] = rs[pre], change(ls[now], ls[pre], L, mid, pos);
    22     else ls[now] = ls[pre], change(rs[now], rs[pre], mid + 1, R, pos);
    23 }
    24 inline int query(int nowl, int nowr, int L, int R, int k){
    25     if(L == R) return L;
    26     int mid = L + R >> 1, minused = seg[rs[nowr]] - seg[rs[nowl]];
    27     if(k <= minused) return query(rs[nowl], rs[nowr], mid + 1, R, k);
    28     else return query(ls[nowl], ls[nowr], L, mid, k - minused);
    29 }
    30 int st[19][N], dfn[N], out[N], tim;
    31 inline void dfs(int x){
    32     dfn[x] = ++ tim;
    33     if(x <= n) change(root[dfn[x]], root[dfn[x] - 1], 1, _n, h[x]);
    34     else root[dfn[x]] = root[dfn[x] - 1];
    35     for(Rint i = head[x];i;i = nxt[i]) dfs(to[i]);
    36     out[x] = tim;
    37 }
    38 inline int query(int v, int x, int k){
    39     for(Rint i = 18;~i;i --)
    40         if(st[i][v] && val[st[i][v]] <= x) v = st[i][v];
    41     int lx = root[dfn[v] - 1], rx = root[out[v]];
    42     return seg[rx] - seg[lx] >= k ? b[query(lx, rx, 1, _n, k)] : -1;
    43 }
    44 int main(){
    45     scanf("%d%d%d", &n, &m, &q); tot = n;
    46     for(Rint i = 1;i <= n;i ++) scanf("%d", h + i), b[i] = h[i];
    47     sort(b + 1, b + n + 1);
    48     _n = unique(b + 1, b + n + 1) - b - 1;
    49     for(Rint i = 1;i <= n;i ++) h[i] = lower_bound(b + 1, b + _n + 1, h[i]) - b;
    50     for(Rint i = 1;i <= m;i ++)
    51         scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    52     sort(e + 1, e + m + 1);
    53     for(Rint i = 1;i <= n;i ++) fa[i] = i;
    54     for(Rint i = 1;i <= m && tot < (n << 1) - 1;i ++){
    55         int fa1 = getfa(e[i].u), fa2 = getfa(e[i].v);
    56         if(fa1 != fa2){
    57             ++ tot;
    58             fa[tot] = fa[fa1] = fa[fa2] = tot;
    59             st[0][fa1] = st[0][fa2] = tot;
    60             add(tot, fa1); add(tot, fa2);
    61             val[tot] = e[i].w;
    62         }
    63     }
    64     for(Rint i = tot;i;i --) if(!dfn[i]) dfs(i);
    65     for(Rint i = 1;i <= 18;i ++)
    66         for(Rint j = 1;j <= tot;j ++) st[i][j] = st[i - 1][st[i - 1][j]];
    67     while(q --){
    68         int v, x, k;
    69         scanf("%d%d%d", &v, &x, &k);
    70         printf("%d
    ", query(v, x, k));
    71     }
    72 }
    Luogu4197
  • 相关阅读:
    form表单回车提交
    Mac os x下配置nginx + php
    Mac下git命令自动补全
    关于javascript中的操作符&&和||的最终返回值
    ARM 裸机程序学习 01 点亮LED
    LINUX SHELL 中 2>&1 重定向的问题
    项目经理到底关心项目的什么?——有关外包项目成本的计算
    ARM 裸机程序学习 03 发送SOS信号(汇编 + C)
    ARM 裸机程序学习 02 按响BEEP
    备忘录 Linux及其内核杂项知识
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/10682931.html
Copyright © 2011-2022 走看看