【线段树合并】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