luogu P4197 Peaks

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
正常
离线是个好东西

posted @ 2019-09-05 20:04  lahlah  阅读(29)  评论(0编辑  收藏  举报