luogu P4197 Peaks
题目大意很清楚了,就不解释了
第一眼kruskal重构树 + 主席树毒瘤码农题
然后发现貌似可以离线
然后就可以愉快地线段树合并 + 并查集了
具体思路就是
先把所有的边按照边权排序,然后再把询问按照x排序(从小到大)
然后对于每个点维护一个动态开点线段树
询问时 如果当前边边权小于x就把u,v对应的线段树合并一下(用并查集维护连通性)
然后就很愉快了
code:
#include<bits/stdc++.h>
#define N 1000005
using namespace std;
struct A{int u, v, c;} a[N];
int cmp(A x, A y){
return x.c < y.c;
}
struct Q{int u, x, k, id;} q[N];
int cmp1(Q x, Q y){
return x.x < y.x;
}
int fa[N];
int get(int x){
return x == fa[x]? x:(fa[x] = get(fa[x]));
}
int size[N << 5], ch[N << 5][2], tot;
void insert(int &rt, int l, int r, int x){
if(!rt) rt = ++ tot;
size[rt] ++;
if(l == r) return;
int mid = (l + r) >> 1;
if(x <= mid) insert(ch[rt][0], l, mid, x);
else insert(ch[rt][1], mid + 1, r, x);
}
int merge(int x, int y){
if(!x && !y) return 0;
if(!x) return y;
if(!y) return x;
size[x] += size[y];
ch[x][0] = merge(ch[x][0], ch[y][0]);
ch[x][1] = merge(ch[x][1], ch[y][1]);
return x;
}
int find(int rt, int l, int r, int k){
if(l == r) return l;
int mid = (l + r) >> 1;
if(size[ch[rt][0]] >= k) return find(ch[rt][0], l, mid, k);
else return find(ch[rt][1], mid + 1, r, k - size[ch[rt][0]]);
}
int n, m, Q, h[N], b[N], root[N], ANS[N];
int main(){
scanf("%d%d%d", &n, &m, &Q);
for(int i = 1; i <= n; i ++) scanf("%d", &h[i]), b[i] = h[i];
sort(b + 1, b + 1 + n);
for(int i = 1; i <= n; i ++){
int pos = lower_bound(b + 1, b + 1 + n, h[i]) - b; //离散化
insert(root[i], 1, n, pos); fa[i] = i;//对于每个点维护一个动态开点线段树
}
for(int i = 1; i <= m; i ++) scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].c);
for(int i = 1; i <= Q; i ++) scanf("%d%d%d", &q[i].u, &q[i].x, &q[i].k), q[i].id = i;
sort(a + 1, a + 1 + m, cmp);
sort(q + 1, q + 1 + Q, cmp1);//把边和边权离线
int pos = 0;
for(int i = 1; i <= Q; i ++){
while(a[pos + 1].c <= q[i].x && pos < m){//把满足条件的边插进去
int x = get(a[pos + 1].u), y = get(a[pos + 1].v);//找ba ba
if(x != y){//如果不在同一个连通块
merge(root[x], root[y]);//线段树合并
fa[y] = x;
}
pos ++;
}
int x = get(q[i].u);
if(size[root[x]] < q[i].k) ANS[q[i].id] = -1;
else ANS[q[i].id] = b[find(root[x], 1, n, size[root[x]] - q[i].k + 1)];//因为时第k大,所以要变一下
}
for(int i = 1; i <= Q; i ++) printf("%d\n", ANS[i]);//输出
return 0;
}
竟然1A,好感动QWQ
正常
离线是个好东西