zoukankan      html  css  js  c++  java
  • P2633 Count on a tree

    Description

    题目描述
    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

    Solution

    按照dfs序建主席树, 那么l, r的答案就是(R_l+R_r-R_{lca}-R_{lca_fa}).

    Code

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    const int N = 100005;
    
    struct Edge {
    	int v, nxt;
    } e[N << 1];
    int head[N], tot;
    void AddEdge(int u, int v) {
    	e[++tot] = (Edge) {v, head[u]}; head[u] = tot;
    	e[++tot] = (Edge) {u, head[v]}; head[v] = tot;
    }
    
    struct Node {
    	int val;
    	Node *ls, *rs;
    	Node() { ls = rs = NULL, val = 0; }
    	Node(Node* co) : Node() { val = co->val; }
    	void update() { val = ls->val + rs->val; }
    	void clear() { if (ls) ls->clear(), rs->clear(); delete this; }
    };
    
    class Tree {
    private:
    	int n;
    	std:: vector<Node*> R;
    	void build(int l, int r, Node* node) {
    		if (l == r) return;
    		int mid = l + r >> 1;
    		node->ls = new Node();
    		node->rs = new Node();
    		build(l, mid, node->ls);
    		build(mid + 1, r, node->rs);
    	}
    	void rebuild(int l, int r, int p, Node* node, Node* pre) {
    		if (l == r) {
    			node->val += 1;
    			return;
    		}
    		int mid = l + r >> 1;
    		if (p <= mid) {
    			node->rs = pre->rs;
    			node->ls = new Node(pre->ls);
    			rebuild(l, mid, p, node->ls, pre->ls);
    		} else if (p > mid) {
    			node->ls = pre->ls;
    			node->rs = new Node(pre->rs);
    			rebuild(mid + 1, r, p, node->rs, pre->rs);
    		}
    		node->update();
    	}
    	Node* merge(Node *l, Node *r) {
    		if (not l and not r) return NULL;
    		if (not l) return r; if (not r) return l;
    		Node* res = new Node();
    		res->val = l->val + r->val;
    		res->ls = merge(l->ls, r->ls);
    		res->rs = merge(l->rs, r->rs);
    		return res;
    	}
    	int kth_query(int l, int r, int k, Node *a, Node *b) {
    		if (l == r) return l;
    		int mid = l + r >> 1;
    		int val = b->ls->val - a->ls->val;
    		if (val < k)
    			return kth_query(mid + 1, r, k - val, a->rs, b->rs);
    		else return kth_query(l, mid, k, a->ls, b->ls);
    	}
    public:
    	void build(int _) {
    		for (int i = 0; i < _; i += 1)
    			R.push_back(new Node());
    		n = _; build(1, n, R[0]);
    	}
    	void rebuild(int p, int now, int fa) {
    		rebuild(1, n, p, R[now], R[fa]);
    	}
    	int get(int l, int r, int ll, int rr, int p) {
    		Node *he1 = merge(R[l], R[r]), *he2 = merge(R[ll], R[rr]);
    		return kth_query(1, n, p, he1, he2);
    	}
    };
    
    int f[N][20], dep[N];
    int val[N], A[N];
    int cnt;
    #define getval(X) std:: lower_bound(A + 1, A + cnt + 1, X) - A
    void dfs(int u, int fa, Tree* T) {
    	T->rebuild(getval(u), u, fa);
    	f[u][0] = fa; dep[u] = dep[fa] + 1;
    	for (int i = head[u]; i; i = e[i].nxt) {
    		if (u == fa) continue;
    		dfs(e[i].v, u, T);
    	}
    }
    int lca(int u, int v) {
    	if (dep[u] < dep[v]) std:: swap(u, v);
    	for (int i = 19; ~i; i -= 1)
    		if (dep[f[u][i]] >= dep[v]) 
    			u = f[u][i];
    	for (int i = 19; ~i; i -= 1)
    		if (f[u][i] != f[v][i]) 
    			u = f[u][i], v = f[v][i];
    	return u == v ? u : f[u][0];
    }
    
    int main () {
    	int n, m;
    	scanf("%d%d", &n, &m); 
    	for (int i = 1; i <= n; i += 1)
    		scanf("%d", &val[i]), A[i] = val[i];
    	std:: sort(A + 1, A + n + 1);
    	cnt = std:: unique(A + 1, A + n + 1) - A - 1;
    	for (int i = 1; i < n; i += 1) {
    		int u, v; scanf("%d%d", &u, &v);
    		AddEdge(u, v);
    	}
    	Tree* T = new Tree();
    	T->build(n);
    	dfs(1, 0, T);
    	for (int i = 1; i < 20; i += 1)
    		for (int j = 1; j <= n; j += 1)
    			f[j][i] = f[f[j][i - 1]][i - 1];
    	int lastans = 0;
    	for (int i = 0; i < m; i += 1) {
    		int u, v, w, Lca; scanf("%d%d%d", &u, &v, &w); 
    		u ^= lastans; Lca = lca(u, v);
    		printf("%d
    ", A[T->get(u, v, Lca, f[Lca][0], w)]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    338. 比特位计数
    300.最长上升子序列
    git 钩子服务代码
    thinkphp5.1 封装文件上传模块
    Theano 基础
    使用anaconda和pycharm搭建多python本版的开发环境
    GIT常用命令
    Thinkphp 获取数据表随机值
    在Windows中利用.bat提交git代码到不同分支
    Windows .bat 常量
  • 原文地址:https://www.cnblogs.com/qdscwyy/p/9807071.html
Copyright © 2011-2022 走看看