• P4197 Peaks


    (color{#0066ff}{题目描述})

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

    (color{#0066ff}{输入格式})

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

    (color{#0066ff}{输出格式})

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

    (color{#0066ff}{输入样例})

    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
    

    (color{#0066ff}{输出样例})

    6
    1
    -1
    8
    

    (color{#0066ff}{数据范围与提示})

    (N leq 10^5, 0 leq M, Q leq 5 * 10^5, h_i, c, x leq 10^9)

    (color{#0066ff}{题解})

    Kruskal重构树

    以困难程度为关键字建立大根堆

    倍增找到最浅点

    对于子树内的叶子,就是能到的所有点

    找到这些点的第k大

    考虑dfs序

    只记录叶子节点的dfs序

    同一子树内dfs序连续

    用主席树维护就行了

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; int x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int maxn = 8e5 + 100;
    struct tree {
    protected:
    	struct node {
    		int num;
    		node *ch[2];
    		node(int num = 0): num(num) {
    			ch[0] = ch[1] = NULL;
    		}
    		void *operator new (size_t) {
    			static node *S = NULL, *T = NULL;
    			return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    		}
    	};
    	node *root[maxn];
    	void ins(node *&o, node *ls, int l, int r, int val) {
    		o = new node();
    		*o = *ls;
    		o->num++;
    		if(l == r) return;
    		int mid = (l + r) >> 1;
    		if(val <= mid) ins(o->ch[0], ls->ch[0], l, mid, val);
    		else ins(o->ch[1], ls->ch[1], mid + 1, r, val);
    	}
    	int query(node *x, node *y, int l, int r, int k) {
    		if(l == r) return l;
    		int siz = y->ch[0]->num - x->ch[0]->num;
    		int mid = (l + r) >> 1;
    		if(k <= siz) return query(x->ch[0], y->ch[0], l, mid, k);
    		else return query(x->ch[1], y->ch[1], mid + 1, r, k - siz);
    	}
    	void init() {
    		root[0] = new node();
    		root[0]->ch[0] = root[0]->ch[1] = root[0];
    	}
    public:
    	tree() { init(); }
    	void ins(int *s, int *t, int *m, int n, int len) {
    		for(int i = 1; i <= n; i++) ins(root[i], root[i - 1], 1, len, std::lower_bound(t + 1, t + len + 1, s[m[i]]) - t);
    	}
    	int query(int l, int r, int k, int len) { return query(root[l - 1], root[r], 1, len, k); }
    };
    int n, m, q;
    struct E {
    	int x, y, z;
    	bool operator < (const E &b) const {
    		return z < b.z;
    	}
    }e[maxn];
    struct node {
    	int to;
    	node *nxt;
    	node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
    	void *operator new (size_t) {
    		static node *S = NULL, *T = NULL;
    		return (S == T) && (T = (S = new node[1024]) + 1024), S++;
    	}
    };
    node *head[maxn];
    tree s;
    int h[maxn], l[maxn], r[maxn], fa[maxn], hh[maxn], len = 1;
    int findset(int x) { return x == fa[x]? fa[x] : fa[x] = findset(fa[x]); }
    int f[maxn][26], dfn, redfn[maxn];
    void add(int from, int to) {
    	head[from] = new node(to, head[from]);
    }
    void dfs(int x, int ff) {
    	f[x][0] = ff;
    	if(x <= n) redfn[++dfn] = x;
    	else l[x] = dfn + 1;
    	for(node *i = head[x]; i; i = i->nxt) 
    		if(i->to != ff) dfs(i->to, x);
    	if(x > n) r[x] = dfn;
    }
    int query(int v, int x, int k) {
    	for(int i = 24; i >= 0; i--) if(f[v][i] && h[f[v][i]] <= x) v = f[v][i];
    	if(r[v] - l[v] + 1 < k) return -1;
    	return hh[s.query(l[v], r[v], r[v] - l[v] + 2 - k, len)];
    }
    int main() {
    	n = in(), m = in(), q = in();
    	for(int i = 1; i <= n; i++) hh[i] = h[i] = in(), fa[i] = i;
    	for(int i = 1; i <= m; i++) e[i].x = in(), e[i].y = in(), e[i].z = in();
    	std::sort(hh + 1, hh + n + 1);
    	std::sort(e + 1, e + m + 1);
    	for(int i = 2; i <= n; i++) if(hh[i] != hh[i - 1]) hh[++len] = hh[i];
    	int cnt = n, tot = 0;
    	for(int i = 1; i <= m; i++) {
    		int x = findset(e[i].x);
    		int y = findset(e[i].y);
    		if(x != y) {
    			fa[x] = fa[y] = ++cnt;
    			fa[cnt] = cnt;
    			h[cnt] = e[i].z;
    			add(cnt, x), add(cnt, y);
    			tot++;
    		}
    		if(tot == n - 1) break;
    	}
    	dfs(cnt, 0);
    	for(int j = 1; j <= 24; j++)
    		for(int i = 1; i <= cnt; i++) 
    			f[i][j] = f[f[i][j - 1]][j - 1];
    	s.ins(h, hh, redfn, n, len);
    	int v, x, k;
    	while(q --> 0) {
    		v = in(), x = in(), k = in();
    		printf("%d
    ", query(v, x, k));
    	}
    	return 0;
    }
    
  • 相关阅读:
    ScrollView 实现循环轮播
    UINavigationController和UITabBarController合用
    iOS开发网络篇—网络编程基础
    iOS开发网络篇—搭建本地服务器
    iOS开发网络篇—HTTP协议
    iOS开发网络篇—GET请求和POST请求
    UIView
    iOS准备程序
    iOS小程序-混合计算器
    IOS入门-计算机小程序
  • 原文地址:https://www.cnblogs.com/olinr/p/10215947.html
Copyright © 2020-2023  润新知