bzoj3545[ONTAK2010]Peaks 线段树合并

Posted Kaiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3545[ONTAK2010]Peaks 线段树合并相关的知识,希望对你有一定的参考价值。

【bzoj3545】[ONTAK2010]Peaks

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

6
1
-1
8

HINT

【数据范围】
N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。

题解

  离散后排序,维护加边顺序,然后就是线段树合并了,权值线段树。

  1 #include<cstring>
  2 #include<cmath>
  3 #include<algorithm>
  4 #include<iostream>
  5 #include<cstdio>
  6 
  7 #define N 100007
  8 #define M 500007
  9 #define ll long long
 10 using namespace std;
 11 inline int read()
 12 {
 13     int x=0,f=1;char ch=getchar();
 14     while(ch>9||ch<0){if (ch==-) f=-1;ch=getchar();}
 15     while(ch<=9&&ch>=0){x=(x<<3)+(x<<1)+ch-0;ch=getchar();}
 16     return x*f;
 17 }
 18 
 19 int n,m,q,sz;
 20 int fa[N],rt[N],ans[M],disc[N],h[N];
 21 int siz[M*10],ls[M*10],rs[M*10];
 22 struct Node
 23 {
 24     int x,y,difficulty;
 25 }a[M];
 26 struct Date
 27 {
 28     int x,limit,k,id;
 29 }b[M];
 30 
 31 int find(int num)
 32 {
 33     if (fa[num]!=num) fa[num]=find(fa[num]);
 34     return fa[num];
 35 }
 36 bool cmp(Node x,Node y)
 37 {
 38     return x.difficulty<y.difficulty;
 39 }
 40 bool cmp1(Date x,Date y)
 41 {
 42     return x.limit<y.limit;
 43 }
 44 
 45 int merge(int x,int y)
 46 {
 47     if (!x)return y;
 48     if (!y)return x;
 49     if (!ls[x]&&!rs[x])
 50     {
 51         siz[x]=siz[x]+siz[y];
 52         return x;
 53     }
 54     ls[x]=merge(ls[x],ls[y]);
 55     rs[x]=merge(rs[x],rs[y]);
 56     siz[x]=siz[ls[x]]+siz[rs[x]];
 57     return x;
 58 }
 59 void ins(int &p,int l,int r,int z)
 60 {
 61     if (!p)p=++sz,siz[p]=1;
 62     if (l==r) return;
 63     int mid=(l+r)>>1;
 64     if (z<=mid)ins(ls[p],l,mid,z);
 65     else ins(rs[p],mid+1,r,z);
 66 }
 67 int query(int p,int l,int r,int rank)
 68 {
 69     if (l==r) return l;
 70     int mid=(l+r)>>1;
 71     if (rank<=siz[ls[p]])return query(ls[p],l,mid,rank);
 72     else return query(rs[p],mid+1,r,rank-siz[ls[p]]);
 73 }
 74 void solve()
 75 {
 76     int now=0;
 77     for (int i=1;i<=q;i++)
 78     {
 79         while(now<m&&a[now+1].difficulty<=b[i].limit)
 80         {
 81             int x=find(a[now+1].x),y=find(a[now+1].y);
 82             if (x!=y)
 83             {
 84                 fa[y]=x;
 85                 rt[x]=merge(rt[x],rt[y]);
 86             }
 87             now++;
 88         }
 89         int x=find(b[i].x);
 90         if (siz[rt[x]]<b[i].k) ans[b[i].id]=-1;
 91         else ans[b[i].id]=disc[query(rt[x],1,n,siz[rt[x]]-b[i].k+1)];
 92     }
 93     for (int i=1;i<=q;i++)
 94         printf("%d\n",ans[i]);
 95 }
 96 int main()
 97 {
 98     freopen("fzy.in","r",stdin);
 99     freopen("fzy.out","w",stdout);
100     
101     n=read(),m=read(),q=read();
102     for (int i=1;i<=n;i++)
103         disc[i]=h[i]=read(),fa[i]=i;
104     sort(disc+1,disc+n+1);
105     for (int i=1;i<=n;i++)
106         h[i]=lower_bound(disc+1,disc+n+1,h[i])-disc;
107     for (int i=1;i<=n;i++)
108         ins(rt[i],1,n,h[i]);
109     
110     for (int i=1;i<=m;i++)
111         a[i].x=read(),a[i].y=read(),a[i].difficulty=read();
112     sort(a+1,a+m+1,cmp);
113     for (int i=1;i<=q;i++)
114         b[i].x=read(),b[i].limit=read(),b[i].k=read(),b[i].id=i;
115     sort(b+1,b+q+1,cmp1);
116     solve();
117 }

 

以上是关于bzoj3545[ONTAK2010]Peaks 线段树合并的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3545ONTAK 2010Peaks & BZOJ 3551ONTAK 2010Peaks加强版 Kruskal重构树

[BZOJ3545][ONTAK2010]Peaks

bzoj3545[ONTAK2010]Peaks 线段树合并

Bzoj3545 [ONTAK2010]Peaks

bzoj3545: [ONTAK2010]Peaks 主席树合并

bzoj 3545/3551: [ONTAK2010]Peaks -- 主席树,最小生成树,倍增