zoukankan      html  css  js  c++  java
  • 【LG3248】[HNOI2016]树

    【LG3248】[HNOI2016]树

    题面

    洛谷

    题解

    因为每次你加入的点是原树上某一棵子树

    那么我们一次加入一个点,代表一棵子树加到大树下面

    那么我们要找到一个点在一个大点中用主席树在(dfs)序中(kth)即可

    询问的话,先将所有的点权(深度)转化为边权

    查询时先将两点跳到它所在大点的根

    再倍增跳到大点1(原树)的下面,再在原树上倍增跳一跳即可。

    虽然说起来容易,但是其实还是很码的qaq。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    using namespace std; 
    
    template<typename T>
    inline void read(T &data) {
        data = 0; T w = 1;
        char ch = getchar();
        while (ch != '-' && (!isdigit(ch))) ch = getchar();
        if (ch == '-') w = -1, ch = getchar();
        while (isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
        data *= w;
    } 
    typedef long long ll; 
    const int MAX_N = 1e5 + 5; 
    int N, M, Q, lg[MAX_N]; 
    namespace Ptree { 
    	struct Node { int ls, rs, v; } t[MAX_N * 20]; 
    	int root[MAX_N], tot; 
    	void build(int &o, int l = 1, int r = N) { 
    		o = ++tot; 
    		if (l == r) return ; 
    		int mid = (l + r) >> 1; 
    		build(t[o].ls, l, mid); 
    		build(t[o].rs, mid + 1, r); 
    	} 
    	void insert(int &o, int p, int v, int l = 1, int r = N) { 
    		o = ++tot, t[o] = t[p]; 
    		t[o].v++; 
    		if (l == r) return ;
    		int mid = (l + r) >> 1; 
    		if (v <= mid) insert(t[o].ls, t[p].ls, v, l, mid); 
    		else insert(t[o].rs, t[p].rs, v, mid + 1, r); 
    	} 
    	int query(int x, int y, int k, int l = 1, int r = N) { 
    		if (l == r) return l; 
    		int mid = (l + r) >> 1, s = t[t[y].ls].v - t[t[x].ls].v; 
    		if (k <= s) return query(t[x].ls, t[y].ls, k, l, mid); 
    		else return query(t[x].rs, t[y].rs, k - s, mid + 1, r); 
    	} 
    } 
    namespace Template {
    	int fa[20][MAX_N], dep[MAX_N], pos[MAX_N], R[MAX_N], cnt, L[MAX_N];
    	struct Graph { int next, to; } e[MAX_N << 1]; int fir[MAX_N], e_cnt; 
    	void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; } 
    	void Add_Edge(int u, int v) { e[e_cnt] = (Graph){fir[u], v}; fir[u] = e_cnt++; } 
    	void dfs(int x, int f) {
    		L[pos[x] = ++cnt] = x; 
    		fa[0][x] = f; 
    		dep[x] = dep[f] + 1; 
    		for (int i = 1; i < 20; i++) fa[i][x] = fa[i - 1][fa[i - 1][x]]; 
    		for (int i = fir[x]; ~i; i = e[i].next) if (e[i].to != f) dfs(e[i].to, x); 
    		R[x] = cnt; 
    	} 
    
    	int Dis(int x, int y) {
    		if (dep[x] < dep[y]) swap(x, y);
    		int res = dep[x] - dep[y];
    		for (int i = 20 - 1; ~i; i--)
    			if (dep[fa[i][x]] >= dep[y]) x = fa[i][x];
    		if (x == y) return res;
    		for (int i = 20 - 1; ~i; i--)
    			if (fa[i][x] != fa[i][y])
    				res += 1 << (i + 1), x = fa[i][x], y = fa[i][y];
    		return res + 2;
    	}
    }
    
    namespace BigTree {
    	int N, fa[20][MAX_N], dep[MAX_N], pre[MAX_N]; 
    	ll dis[20][MAX_N], pos[MAX_N], R[MAX_N], cur, link[MAX_N]; 
    	int getRoot(ll x) { 
    		int l = 1, r = N; 
    		while (l <= r) { 
    			int mid = (l + r) >> 1; 
    			if (pos[mid] <= x) l = mid + 1; 
    			else r = mid - 1; 
    		} 
    		return r;
    	} 
    
    	int getPre(ll x) { 
    		int rt = getRoot(x); 
    		return Ptree::query(Ptree::root[Template::pos[pre[rt]] - 1], Ptree::root[Template::R[pre[rt]]],
    							x - pos[rt] + 1);
    	}
    
    	void Init() { 
    		pos[1] = N = dep[1] = pre[1] = 1; 
    		cur = R[1] = ::N; 
    		int x; ll to; 
    		for (int i = 1; i <= M; i++) { 
    			read(x), read(to); 
    			int rt = getRoot(to); 
    			++N, dep[N] = dep[rt] + 1, link[N] = to, pre[N] = x; 
    			pos[N] = cur + 1, R[N] = cur + Template::R[x] - Template::pos[x] + 1; 
    			cur = R[N], fa[0][N] = rt;
    			dis[0][N] = Template::dep[getPre(to)] - Template::dep[pre[rt]] + 1;
    			for (int j = 1; j < 20; j++)
    				fa[j][N] = fa[j - 1][fa[j - 1][N]], dis[j][N] = dis[j - 1][N] + dis[j - 1][fa[j - 1][N]];
    		}
    	}
    
    	ll Dis(ll x, ll y) {
    		ll ans = 0;
    		int fx = getRoot(x), fy = getRoot(y);
    		if (fx == fy) return Template::Dis(getPre(x), getPre(y));
    		if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
    		ans += Template::dep[getPre(x)] - Template::dep[pre[fx]], x = fx;
    		for (int i = 20 - 1; ~i; i--)
    			if (dep[fa[i][x]] > dep[fy]) ans += dis[i][x], x = fa[i][x];
    		if (getRoot(link[x]) == fy)
    			return ans + 1 + Template::Dis(getPre(link[x]), getPre(y));
    		ans += Template::dep[getPre(y)] - Template::dep[pre[fy]], y = fy;
    		if (dep[x] > dep[y]) ans += dis[0][x], x = fa[0][x];
    		for (int i = 20 - 1; ~i; i--)
    			if (fa[i][x] != fa[i][y]) ans += dis[i][x] + dis[i][y], x = fa[i][x], y = fa[i][y];
    		x = link[x], y = link[y];
    		ans += 2;
    		return ans + Template::Dis(getPre(x), getPre(y));
    	}
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("cpp.in", "r", stdin); 
    #endif
        read(N), read(M), read(Q); 
        for (int i = 2; i <= N; i++) lg[i] = lg[i >> 1] + 1; 
    	Template::clearGraph(); 
        for (int i = 1, a, b; i < N; i++)
            read(a), read(b), Template::Add_Edge(a, b), Template::Add_Edge(b, a);
        Template::dfs(1, 0);
        Ptree::build(Ptree::root[0]);
        for (int i = 1; i <= N; i++) Ptree::insert(Ptree::root[i], Ptree::root[i - 1], Template::L[i]);
        BigTree::Init();
        ll x, y;
        while (Q--) read(x), read(y), printf("%lld
    ", BigTree::Dis(x, y));
        return 0;
    } 
    
  • 相关阅读:
    还是java中的编码问题
    java restful api
    编码方式
    LinkedHash
    Zoj 2562 More Divisors (反素数)
    spark复习总结03
    spark复习总结02
    spark复习总结01
    使用二进制解决一个字段代表多个状态的问题
    spark性能调优05-troubleshooting处理
  • 原文地址:https://www.cnblogs.com/heyujun/p/10447482.html
Copyright © 2011-2022 走看看