zoukankan      html  css  js  c++  java
  • Luogu P4197 Peaks

    题目链接 (Click) (Here)

    做法:(Kruskal)重构树上跑主席树

    构造方法:把每条边拆出来成一个点,点权是原先的边权。每次连边的时候,连的不再是点,而是其原先点所在的联通块。

    (Kruskal)重构树的性质:

    • 二叉树

    • 如果按最小生成树构造,则自顶到底权值递增(堆)

    • 叶节点是原先的树上节点

    • 两个在原图中可以经过权值(<=k)的边互相抵达的点,在最小生成树上也可以这样互相抵达,在(Kruskal)重构树上同理。

    也就是说,假如一个点不能到比它的权值大的点,那么它能抵达的所有点就在它的子树里面。这个题目里我们从询问点跳到权值(<=x)中权值最大的点,其子树中的叶子节点,就是可以询问点可以通过点权(<=x)的点到达的所有点。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 200010;
    const int M = 500010;
    
    int n, m, q, tot, INF, h[N], fa[N], val[N];
    struct edge {int nxt, to;} e[N];
    struct _edge {int u, v, w;}_e[M];
    
    bool cmp (_edge lhs, _edge rhs) {
        return lhs.w < rhs.w;
    }
    
    int find (int x) {
        return x == fa[x] ? x : fa[x] = find (fa[x]);
    }
    
    int cnt, head[N];
    
    void add_edge (int u, int v) {
        e[++cnt] = (edge) {head[u], v}; head[u] = cnt;
    }
    
    int rt[N];
    #define mid ((l + r) >> 1)
    
    struct Segment_Node {
        int sz, ls, rs;
    }t[N << 5];
    
    int modify (int _rt, int l, int r, int w) {
        int p = ++rt[0];
        t[p].sz = t[_rt].sz + 1;
        if (l != r) {
            if (w <= mid) {
                t[p].ls = modify (t[_rt].ls, l, mid, w), t[p].rs = t[_rt].rs;
            } else {
                t[p].rs = modify (t[_rt].rs, mid + 1, r, w), t[p].ls = t[_rt].ls;
            }
        } else {
            t[p].ls = t[p].rs = 0;
        }
        return p;
    }
    
    int sz[N], id[N], dfn[N], deep[N], fafa[N][20], totsize[N];
    
    int sep[N];
    
    int num (int x) {
        return lower_bound (sep + 1, sep + 1 + sep[0], x) - sep;
    }
    
    void dfs (int u, int _fa) {
        sz[u] = head[u] == 0;
    	dfn[u] = ++dfn[0];
    	totsize[u] = 1;
    	id[dfn[0]] = u;
    	fafa[u][0] = _fa;
        deep[u] = deep[_fa] + 1;
        rt[u] = modify (rt[id[dfn[u] - 1]], 1, INF, num (h[u])); //主席树维护高度
        for (int i = 1; (1 << i) <= deep[u]; ++i) {
            fafa[u][i] = fafa[fafa[u][i - 1]][i - 1];
        }
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (v != _fa) {
                dfs (v, u);
                sz[u] += sz[v];
                totsize[u] += totsize[v];
            }
        }
    }
    
    int query (int u, int v, int l, int r, int k) {
        while (l < r) {
            int rch = t[t[v].rs].sz - t[t[u].rs].sz;
            if (k <= rch) {
                u = t[u].rs;
                v = t[v].rs;
                l = mid + 1;
            } else {
                u = t[u].ls;
                v = t[v].ls;
                k -= rch;
                r = mid;
            } 
        }
        return l;
    }
    
    int read () {
    	int s = 0, w = 1, ch = getchar ();
    	while ('9' < ch || ch < '0') {
    		if (ch == '-') w = -1;
    		ch = getchar ();
    	}
    	while ('0' <= ch && ch <= '9') {
    		s = (s << 1) + (s << 3) + ch - '0';
    		ch = getchar ();
    	}
    	return s * w;
    } 
    
    int main () {
    	memset (val, 0x3f, sizeof (val));
    	tot = n = read (), m = read (), q = read ();
        t[0].sz = t[0].ls = t[0].rs = 0, sep[++sep[0]] = 0;
        for (int i = 1; i <= n; ++i) sep[++sep[0]] = h[i] = read ();
        for (int i = 1; i <= m; ++i) {
    	    _e[i].u = read ();
    	    _e[i].v = read ();
    		_e[i].w = read ();
        }
        sort (_e + 1, _e + 1 + m, cmp);
        for (int i = 1; i <= n; ++i) fa[i] = i;
        for (int i = 1; i <= m; ++i) {
            int u = find (_e[i].u);
            int v = find (_e[i].v);
            if (u != v) {
                int T = ++tot;
                val[T] = _e[i].w;
                fa[u] = fa[v] = fa[T] = T;
                add_edge (T, u);
                add_edge (T, v);
            }
        }
        sort (sep + 1, sep + 1 + sep[0]);
        INF = sep[0] = unique (sep + 1, sep + 1 + sep[0]) - sep - 1;
        dfs (tot, 0);
    	int lastans = 0;
        for (int i = 1; i <= q; ++i) {
            int u = read () ^ lastans;
    		int x = read () ^ lastans;
    		int k = read () ^ lastans;
            for (int j = 19; j >= 0; --j) {
    			if (val[fafa[u][j]] <= x) {
                    u = fafa[u][j];
                }
            }
            if (sz[u] < k) {
                puts ("-1");
    			lastans = 0;
            } else {
    			lastans = sep[query (rt[id[dfn[u] - 1]], rt[id[dfn[u] + totsize[u] - 1]], 1, INF, k)];
                printf ("%d
    ", lastans);
            }
        }
    }
    
    
  • 相关阅读:
    用react重构个人网站 3-23
    用react重构个人网站 3-22
    React官方文档笔记之快速入门
    .Net多线程编程—同步机制
    .Net多线程编程—Parallel LINQ、线程池
    .Net多线程编程—并发集合
    .Net多线程编程—任务Task
    【翻译】MongoDB指南/聚合——聚合管道
    【翻译】MongoDB指南/CRUD操作(四)
    【翻译】MongoDB指南/CRUD操作(三)
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10548802.html
Copyright © 2011-2022 走看看