【线段树合并】bzoj3545: [ONTAK2010]Peaks

1A还行

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

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

HINT

【数据范围】

N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9。


题目分析

题目所求的是“小于等于x的边”所成连通块中的第k大,这里就会自然想到处理这一类连通块问题的策略:从小到大加边维护连通块,并在这个过程中离线处理查询。

现在要维护的连通块信息是无序的集合,于是第一反应就是用set合并。但是显而易见的是,set不能处理第k大问题(话说暑假做“不等式组”那题时候第一反应就是用multiset处理,但是当时被查询key和第k大困扰了很久)。有一种常见的方法是采用权值线段树实现set的功能,这样一来就可以处理一些基础的查询问题。

处理完了连通块和维护的操作,接下去的问题就是合并。权值线段树本质上还是线段树,所以使用线段树合并的套路就可以保证这一部分的复杂度。

感觉是比较套路和数据结构的题,好像没什么营养……

 

  1 #include<bits/stdc++.h>
  2 const int maxn = 100035;
  3 const int maxq = 500035;
  4 const int maxm = 1000035;
  5 const int maxNode = 4000035;
  6 
  7 struct node
  8 {
  9     int l,r,val;
 10 }a[maxNode];
 11 struct QRs
 12 {
 13     int v,x,k,id;
 14     bool operator < (QRs a) const
 15     {
 16         return x < a.x;
 17     }
 18 }qr[maxq];
 19 struct Edge
 20 {
 21     int u,v,val;
 22     Edge(int a=0, int b=0, int c=0):u(a),v(b),val(c) {}
 23     bool operator < (Edge a) const
 24     {
 25         return val < a.val;
 26     }
 27 }edges[maxm];
 28 int n,m,q,dal,tot,ans[maxq];
 29 int fat[maxn],h[maxn],cnt[maxn],rt[maxn];
 30 
 31 int read()
 32 {
 33     char ch = getchar();
 34     int num = 0, fl = 1;
 35     for (; !isdigit(ch); ch=getchar())
 36         if (ch=='-') fl = -1;
 37     for (; isdigit(ch); ch=getchar())
 38         num = (num<<1)+(num<<3)+ch-48;
 39     return num*fl;
 40 }
 41 int find(int x){return x==fat[x]?x:fat[x]=find(fat[x]);}
 42 int query(int rt, int l, int r, int c)
 43 {
 44     if (l==r) return l;
 45     int mid = (l+r)>>1;
 46     if (c <= a[a[rt].l].val)
 47         return query(a[rt].l, l, mid, c);
 48     return query(a[rt].r, mid+1, r, c-a[a[rt].l].val);
 49 }
 50 int queryPos(int v, int k)
 51 {
 52     int anc = find(v);
 53     if (a[rt[anc]].val < k) return -1;
 54     return cnt[query(rt[anc], 1, cnt[0], a[rt[anc]].val-k+1)];
 55 }
 56 void update(int &rt, int l, int r, int c)
 57 {
 58     if (!rt) rt = ++tot;
 59     ++a[rt].val;
 60     if (l==r) return;
 61     int mid = (l+r)>>1;
 62     if (c <= mid) update(a[rt].l, l, mid, c);
 63     else update(a[rt].r, mid+1, r, c);
 64 }
 65 void merge(int &u, int v)
 66 {
 67     if (u*v==0){
 68         u = u?u:v;
 69         return;
 70     }
 71     a[u].val += a[v].val;
 72     merge(a[u].l, a[v].l);
 73     merge(a[u].r, a[v].r);
 74 }
 75 int main()
 76 {
 77     n = read(), m = read(), q = read();
 78     for (int i=1; i<=n; i++) h[i] = cnt[i] = read(), fat[i] = i;
 79     for (int i=1; i<=m; i++)
 80         edges[i].u = read(), edges[i].v = read(), edges[i].val = read();
 81     for (int i=1; i<=q; i++)
 82         qr[i].v = read(), qr[i].x = read(), qr[i].k = read(), qr[i].id = i;
 83     std::sort(edges+1, edges+m+1);
 84     std::sort(cnt+1, cnt+n+1);
 85     std::sort(qr+1, qr+q+1);
 86     cnt[0] = std::unique(cnt+1, cnt+n+1)-cnt-1;
 87     for (int i=1; i<=n; i++)
 88     {
 89         h[i] = std::lower_bound(cnt+1, cnt+cnt[0]+1, h[i])-cnt;
 90         update(rt[i], 1, cnt[0], h[i]);
 91     }
 92     dal = 1;
 93     for (int i=1; i<=m; i++)
 94     {
 95         int fu = find(edges[i].u), fv = find(edges[i].v);
 96         if (fu!=fv){
 97             for (; dal<=q&&qr[dal].x < edges[i].val; ++dal)
 98                 ans[qr[dal].id] = queryPos(qr[dal].v, qr[dal].k);
 99             fat[fu] = fv, merge(rt[fv], rt[fu]);
100         }
101     }
102     for (int i=dal; i<=q; i++)
103         ans[qr[i].id] = queryPos(qr[i].v, qr[i].k);
104     for (int i=1; i<=q; i++) printf("%d\n",ans[i]);
105     return 0;
106 }

 

 

 

 

END

转载于:https://www.cnblogs.com/antiquality/p/10290425.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值