Count on a tree

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

Input
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
Output
M行,表示每个询问的答案。最后一个询问不输出换行符

Sample Input
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
Sample Output
2
8
9
105
7

Hint
N,M<=100000

标签:DFS序+LCA+值域主席树

这时一个区间第k小的问题,所以可以很自然的想到值域主席树。但是此题将区间移到了树上,在树上套线段树,可以想到DFS序和树链剖分。此题应该是DFS序。
在解区间第k小的时候,对于每次询问区间[a,b],我们需要找到a-1位置的线段树和b位置的线段树,然后递归query的时候用个数相减。对于这道题,我们把每个结点到根的那条链作为一个序列,用区间第k小的方法存储,然后找到u和v的LCA(假定它为t),递归query的时候计算左区间数的个数,即u结点对应线段树左区间数的个数+v结点....数的个数-t结点...数的个数-t的父结点...数的个数。即tmp = tr[tr[u].ls].val+tr[tr[v].ls].val-tr[tr[t].ls].val-tr[tr[fa[t]].ls].val。
写的时候注意强制在线的操作方式和读入数后先离散化。

最后附上AC代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAX_N 100000
using namespace std;
int n, m, c[MAX_N+5];
int cnt = 0, root[MAX_N+5];
int tot = 0, map[MAX_N+5];
int anc[MAX_N+5][25], dep[MAX_N+5];
bool vis[MAX_N+500];
vector <int> G[MAX_N+500];
struct Pre {int id, val;} pre[MAX_N+5];
struct TNode {int ls, rs, val;} tr[MAX_N*32+500];
bool cmp(const Pre &a, const Pre &b) {return a.val < b.val;}
void DFS(int u) {vis[u] = true;for (int i = 1; (1<<i) <= dep[u]; i++)  anc[u][i] = anc[anc[u][i-1]][i-1];for (int i = 0; i < G[u].size(); i++) {int v = G[u][i];if (!vis[v])    anc[v][0] = u, dep[v] = dep[u]+1, DFS(v);}
}
int LCA(int a, int b) {int i, j;if (dep[a] < dep[b])    swap(a, b);for (i = 0; (1<<i) <= dep[a]; i++) ;    i--;for (j = i; j >= 0; j--)if (dep[a]-(1<<j) >= dep[b])a = anc[a][j];if (a == b) return a;for (j = i; j >= 0; j--)if (anc[a][j] != anc[b][j])a = anc[a][j], b = anc[b][j];return anc[a][0];
}
void init(int &v, int s, int t) {v = ++cnt;if (s == t) return;int mid = s+t>>1;init(tr[v].ls, s, mid);init(tr[v].rs, mid+1, t);
}
void insert(int v, int o, int s, int t, int val) {tr[v] = tr[o];if (s == t) {tr[v].val++;   return;}int mid = s+t>>1;if (val <= mid) insert(tr[v].ls = ++cnt, tr[o].ls, s, mid, val);else    insert(tr[v].rs = ++cnt, tr[o].rs, mid+1, t, val);tr[v].val = tr[tr[v].ls].val+tr[tr[v].rs].val;
}
void build(int u) {root[u] = ++cnt;insert(root[u], root[anc[u][0]], 1, tot, c[u]);for (int i = 0; i < G[u].size(); i++) {int v = G[u][i];if (v != anc[u][0]) build(v);}
}
int query(int v1, int v2, int v3, int v4, int s, int t, int k) {if (s == t) return s;int mid = s+t>>1, tmp = tr[tr[v1].ls].val+tr[tr[v2].ls].val-tr[tr[v3].ls].val-tr[tr[v4].ls].val;if (k <= tmp)   return query(tr[v1].ls, tr[v2].ls, tr[v3].ls, tr[v4].ls, s, mid, k);return query(tr[v1].rs, tr[v2].rs, tr[v3].rs, tr[v4].rs, mid+1, t, k-tmp);
}
int main() {scanf("%d%d", &n, &m);for (int i = 1; i <= n; i++)    pre[i].id = i, scanf("%d", &pre[i].val);sort(pre+1, pre+n+1, cmp);for (int i = 1; i <= n; i++) {if (i == 1 || pre[i].val != pre[i-1].val)   map[++tot] = pre[i].val;c[pre[i].id] = tot;}for (int i = 1; i < n; i++) {int u, v;scanf("%d%d", &u, &v);G[u].push_back(v), G[v].push_back(u);}DFS(1);init(root[0], 1, tot), build(1);int ans = 0;while (m--) {int u, v, k;scanf("%d%d%d", &u, &v, &k);    u ^= ans;int lca = LCA(u, v);ans = map[query(root[u], root[v], root[lca], root[anc[lca][0]], 1, tot, k)];printf("%d", ans);if (m >= 1) printf("\n");}return 0;
}

转载于:https://www.cnblogs.com/AzraelDeath/p/7561746.html

BZOJ2588 Count on a tree DFS序+LCA+值域主席树相关推荐

  1. 牛客 - Colorful Tree(dfs序+LCA)

    题目链接:点击查看 题目大意:给出一棵 n 个节点构成的数,每个节点都有一个颜色,现在需要执行 m 次操作,每次操作分为如下两种类型: Q x:回答所有颜色为 x 的节点构成的连通子图含有的最少边数 ...

  2. BZOJ4771 七彩树(dfs序+树上差分+主席树)

    考虑没有深度限制怎么做.显然的做法是直接转成dfs序上主席树,但如果拓展到二维变成矩形数颜色数肯定没法做到一个log. 另一种做法是利用树上差分.对于同种颜色的点,在每个点处+1,dfs序相邻点的lc ...

  3. 牛客 - 红蓝图(克鲁斯卡尔重构树的dfs序上建主席树)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,每条边都有边权和颜色,颜色分为红色和蓝色,现在有 q 次相互独立的操作,每次操作会询问 ( x , t ) ,问删除掉所有权值 ...

  4. CodeForces - 1328E Tree Queries(dfs序/LCA)

    题目链接:点击查看 题目大意:给出一棵以点 1 为根节点的树,接下来有 m 次询问,每次询问给出 k 个点,题目问我们能否找到一个点 u ,使得从根节点到点 u 的简单路径,到 k 个点的每个点的距离 ...

  5. BZOJ2588 Count on a tree 【树上主席树】

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MB Submit: 7577  Solved: 185 ...

  6. [codeforces] 383C Propagating tree(dfs序+线段树)

    题意: 给你一棵n个结点的树, 以1为根.每个结点有点权.有m次操作: 1.x结点权值 +val,x的儿子权值 −val,x的孙子们 +val,以此类推. 2.询问x的点权: 题解: 我们首先跑一边d ...

  7. Innumerable Ancestors 尺取 dfs序 lca

    给一棵树,m次查询,每次查询给两个集合,从这两个集合中分别选一个结点,使得这两个结点的lca的深度最大 考虑dfs序为3, 4, 5的三个结点,3和4的lca深度一定大于等于3和5的lca深度 所以可 ...

  8. [Split The Tree][dfs序+树状数组求区间数的种数]

    Split The Tree 时间限制: 1 Sec  内存限制: 128 MB 提交: 46  解决: 11 [提交] [状态] [讨论版] [命题人:admin] 题目描述 You are giv ...

  9. 牛客多校2 - Cover the Tree(dfs序)

    题目链接:点击查看 题目大意:给出一棵无根树,问能否选择数量最少的链,使得所有的路径都被覆盖到 题目分析:读完题后不难看出,假设叶子结点的个数为 x,那么答案就是 x / 2 向上取整 然后说结论,d ...

最新文章

  1. 一条直线上N个线段所覆盖的总长度
  2. git粘贴命令行_git进阶,ssh和命令行
  3. 输入对话框基于PyQt4的输入对话框
  4. Java Web(5) Spring 下使用Junit4 单元测试
  5. CreateJS基础 学习笔记(上)
  6. Rx:4-[编外篇] .NET4里的Concurrent Collections
  7. python 异常点检测 cook距离_DLI 精选课程 | 三种AI方法检测网络、业务或设备异常状况...
  8. CentOS FireFox Flash Player
  9. 网上购物与开店赢家随身查
  10. 【劲峰论道时空分析技术-学习笔记】5 时空格局和异常探测
  11. is_file() 和 is_dir()注意事项
  12. 【设计模式】工厂模式
  13. hp服务器经常自动重启,惠普电脑经常自动重启的解决方法
  14. 数字化背景下的经济社会发展的新特征 新趋势
  15. Mysql 给时间增加对应的时间
  16. PXE网络安装linux系统
  17. 产品分析————拼多多
  18. js中的颜色对应的常量代码code
  19. python逻辑回归的主要参数_python机器学习(六)回归算法-逻辑回归
  20. 记一次gitbook的安装

热门文章

  1. Thread Dump 和Java应用诊断(转)
  2. WPF怎么寻找在ItemTemplate内部的各种控件
  3. 运维需要掌握的基础知识
  4. 选本还是从缓存设计理念选择更好
  5. Windows7操作系统自定义运行命令(简单方法之二)
  6. Fedora安装Samba与windows共享文件
  7. Visual Studio 2010 and .NET 4 RTM中文版发布
  8. 转:设置session过期时间
  9. ruby require的使用
  10. 驱动学习之LED驱动框架