zoukankan      html  css  js  c++  java
  • 题解 P4197 【Peaks】

    首先用\(Kruskal\)重构树,这样我们就能很方便的处理比\(x\)小的限制条件了

    然后它询问的是高度中的第\(k\)大,会自然地想到要用主席树,只是说,要注意一个细节。

    不难发现,重构树的某一个非叶节点(边)会管辖某些叶子节点(点),有趣的是,其管辖的叶子节点构成一个区间,换而言之是连续的(想不出来的可以画一张图\(QAQ\)

    所以我可以先\(Kruskal\)重构树,然后做一遍\(dfs\),这遍\(dfs\)的过程中,我们把所有的叶子节点 "摘" 下来,形成一个序列,并对每个节点维护其管辖的区间。

    然后每次询问就变成了:先在重构树上跳,跳到某个节点\(x\)后询问\(L[x]\)\(R[x]\)这一段区间内第\(k\)大的数是谁?—主席树板子

    然后注意离散化,以及特判无解的情况。下面是丑陋的代码。

    
    #include<bits/stdc++.h>
    using namespace std;
    int read(){
    	char cc = getchar(); int cn = 0, flus = 1;
    	while(cc < '0' || cc > '9'){
        	if(cc == '-') flus = -flus;
    		cc = getchar();
    	}
    	while(cc >= '0' && cc <= '9')
    	    cn = cn * 10 + cc - '0', cc = getchar();
    	return cn * flus;
    }
    const int N = 2e5 + 5;
    const int M = 5e5 + 5;
    const int inf = 999999999;
    struct E{
    	int to, next;
    }e[N * 2];
    struct Node{
    	int x, y, z;
    }q[M], hh[N];
    struct Tree{
    	int l, r, val;
    }t[N * 27];
    int h[N], head[N], fa[N], val[N], fath[N][24], L[N], R[N], b[N];
    int n, m, Q, cnt, tot, pop, rot[N], ctt;
    bool cmp(Node x, Node y){
    	return x.z < y.z;
    }
    void add(int x, int y){
    	e[++cnt] = (E){y, head[x]}; head[x] = cnt;
    }
    void input(){
    	n = read(), m = read(), Q = read();
    	val[0] = inf;
    	for(int i = 1; i <= n; i++) h[i] = read(), hh[i].x = i, hh[i].z = h[i];
    	sort(hh + 1, hh + n + 1, cmp);
    	for(int i = 1; i <= n; i++) h[hh[i].x] = i;
    	for(int i = 1; i <= m; i++)
    		q[i].x = read(), q[i].y = read(), q[i].z = read();
    	return ;
    }
    int find(int x){
    	if(fa[x] == x) return x;
    	return fa[x] = find(fa[x]);
    }
    void Kruskal()
    {
    	sort(q + 1, q + m + 1, cmp);
    	for(int i = 1; i <= n; i++) fa[i] = i;
    	tot = n;
    	for(int i = 1; i <= m; i++)
    	{
    		int u = find(q[i].x), v = find(q[i].y);
    		if(u == v) continue;
    		val[++tot] = q[i].z, fa[tot] = fa[u] = fa[v] = tot;
    		add(tot, u), add(tot, v);
    	}
    }
    void dfs(int x, int fa)
    {
    	fath[x][0] = fa;
    	for(int i = 1; i <= 19; i ++)  
    		fath[x][i] = fath[fath[x][i - 1]][i - 1];
    	L[x] = pop;
    	if(head[x] == 0) { b[++pop] = x; R[x] = pop; return ; }
    	for(int i = head[x]; i; i = e[i].next)
    		dfs(e[i].to, x);
    	R[x] = pop;
    }
    //主席树 
    void build(int &root, int ll, int rr)
    {
    	root = ++ctt;
    	if(ll == rr)  return ;
    	int mid = (ll + rr) >> 1;
    	build(t[root].l, ll, mid); build(t[root].r, mid + 1, rr);
    }
    void change(int &root, int node, int ll, int rr, int k)
    {
    	root = ++ctt; t[root] = t[node];
    	if(ll == rr) {  t[root].val ++;  return ; }
    	int mid = (ll + rr) >> 1;
    	if(mid >= k) change(t[root].l, t[node].l, ll, mid, k);
    	else change(t[root].r, t[node].r, mid + 1, rr, k);
    	t[root].val = t[t[root].l].val + t[t[root].r].val;
    }
    int find_tr(int x, int k)
    {
    	int now = x;
    	for(int i = 19; i >= 0; i--)
    		if(val[fath[now][i]] <= k) now = fath[now][i];
    	return now;
    }
    int query(int root1, int root2, int k, int l, int r)
    {
    	int rkid = t[t[root1].r].val - t[t[root2].r].val, mid = (l + r) >> 1;
    	if(l == r){
    		if(k - (t[root1].val - t[root2].val) == 0) //这里注意特判
            	return l;
    		return 0;
    	}
    	if(rkid >= k) return query(t[root1].r, t[root2].r, k, mid + 1, r);
    	else return query(t[root1].l, t[root2].l, k - rkid, l, mid);
    }
    void solve(){
    	Kruskal(), dfs(tot, tot);
    	build(rot[0], 1, n);
    	for(int i = 1; i <= pop; i++)
    		change(rot[i], rot[i - 1], 1, n, h[b[i]]);
    	int v, x, k;
    	hh[0].z = -1;
    	for(int i = 1; i <= Q; i++)
    	{
    		v = read(), x = read(), k = read();
    		int vip = find_tr(v, x);
    		int ans = query(rot[R[vip]], rot[L[vip]], k, 1, n);
    		printf("%d\n", hh[ans].z);
    	}
    }
    signed main()
    {
    	input();
    	solve();
    	return 0;
    }
    
    
  • 相关阅读:
    Android Dalvik 虚拟机
    我在北京找工作(二):java实现算法<1> 冒泡排序+直接选择排序
    如何用java比较两个时间或日期的大小
    [安卓破解]听网页浏览器,无需注册即可语音朗读
    (step8.2.4)hdu 1846(Brave Game——巴什博奕)
    Oracle Database 12c Release 1 Installation On Oracle Linux 6.4 x86_64
    HDU2084:数塔(DP)
    MySQL MVCC(多版本并发控制)
    POJ
    网易前端微专业,JavaScript程序设计基础篇:数组
  • 原文地址:https://www.cnblogs.com/Soulist/p/10587952.html
Copyright © 2011-2022 走看看