zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    179     }
    180 }
  • 相关阅读:
    创意工坊pkg食用
    wordpress添加备案号出现乱码
    「Azure」数据分析师有理由爱Azure之四-Azure SQL的实操
    「Azure」数据分析师有理由爱Azure之三-对照Sqlserver学Azure
    「Azure」数据分析师有理由爱Azure之二-立即申请帐号开始学习之旅
    「Azure」数据分析师有理由爱Azure之一-Azure能带给我们什么?
    「Sqlserver」数据分析师有理由爱Sqlserver之十-Sqlserver自动化篇
    「Sqlserver」数据分析师有理由爱Sqlserver之九-无利益关系推荐Sqlserver书单
    「Sqlserver」数据分析师有理由爱Sqlserver之八-最刚需的数据导入导出功能-导出篇
    「Sqlserver」数据分析师有理由爱Sqlserver之七-最刚需的数据导入导出功能-导入篇
  • 原文地址:https://www.cnblogs.com/lytccc/p/6635672.html
Copyright © 2011-2022 走看看