SPOJ 10628 Count on a tree (lca+主席树)
题意:给定一棵有n个结点的树,每一个点有一个权值。共同拥有m个询问。对于每一个询问(u,v,k),回答结点u至v之间第k小的点的权值。
思路:主席树+lca。首先指定一个根结点dfs一次并在此过程中建好主席树。对于对于每一个询问,我们仅仅须要考虑四棵树,即T[u], T[v], T[lca(u,v)], 再加上T[fa( lca(u,v) )],fa( lca(u,v) )表示lca(u, v)的父亲结点。
这样一来问题就和线性序列里第k小的数一样了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii (pair<int, int>)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; //const int maxn = 100000 + 100;
//const int INF = 0x3f3f3f3f; const int maxn = 100000+10000;
const int M = 2000000;
int n, q, m, tot;
int t[maxn], w[maxn], fa[maxn];
int T[maxn], lson[M], rson[M], c[M]; struct Quest {
int l, r, k;
} quest[maxn]; void Init_hash(int k) {
sort(t, t+k);
m = unique(t, t+k) - t;
} int Hash(int x) {
return lower_bound(t, t+m, x) - t;
} int build(int l, int r) {
int root = tot++;
c[root] = 0;
if(l != r) {
int mid = (l+r) >> 1;
lson[root] = build(l, mid);
rson[root] = build(mid+1, r);
}
return root;
} int Insert(int root, int pos, int val) {
int newroot = tot++, tmp = newroot;
int l = 0, r = m-1;
c[newroot] = c[root] + val;
while(l < r) {
int mid = (l+r)>>1;
if(pos <= mid) {
lson[newroot] = tot++; rson[newroot] = rson[root];
newroot = lson[newroot]; root = lson[root];
r = mid;
}
else {
rson[newroot] = tot++; lson[newroot] = lson[root];
newroot = rson[newroot]; root = rson[root];
l = mid+1;
}
c[newroot] = c[root] + val;
}
return tmp;
} int Query(int l_root, int r_root, int lca, int k) {
int l = 0, r = m -1, lca_root = T[lca], fa_root = fa[lca];
while(l < r) {
int mid = (l+r) >> 1;
int tmp = c[lson[l_root]]+c[lson[r_root]]-c[lson[lca_root]]-c[lson[fa_root]];
if(tmp >= k) {
r = mid;
l_root = lson[l_root]; r_root = lson[r_root]; lca_root = lson[lca_root]; fa_root = lson[fa_root];
}
else {
l = mid + 1;
k -= tmp;
l_root = rson[l_root]; r_root = rson[r_root]; lca_root = rson[lca_root]; fa_root = rson[fa_root];
}
}
return l;
} int pnt[maxn], lca[maxn];
bool vis[maxn];
vector<int> G[maxn], query[maxn], num[maxn];
int find(int x) {
if(x == pnt[x]) return x;
return pnt[x] = find(pnt[x]);
}
void dfs_lca(int u) {
vis[u] = 1; pnt[u] = u;
int sz1 = G[u].size();
for(int i = 0; i < sz1; i++) {
int v = G[u][i];
if(vis[v]) continue;
fa[v] = T[u];
dfs_lca(v);
pnt[v] = u;
}
int sz2 = query[u].size();
for(int i = 0; i < sz2; i++) {
int v = query[u][i];
if(vis[v]) lca[num[u][i]] = find(v);
}
}
void init() {
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) {
G[i].clear();
query[i].clear();
num[i].clear();
}
} void dfs_ZXTree(int cur, int fa) {
int sz = G[cur].size();
for(int i = 0; i < sz; i++) {
int u = G[cur][i];
if(u == fa) continue;
T[u] = Insert(T[cur], Hash(w[u]), 1);
dfs_ZXTree(u, cur);
}
} int main() {
//freopen("input.txt", "r", stdin);
while(cin >> n >> q) {
init();
m = 0; tot = 0;
for(int i = 1; i <= n; i++) scanf("%d", &w[i]), t[m++] = w[i];
Init_hash(m);
build(0, m-1);
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);
}
T[1] = Insert(T[0], Hash(w[1]), 1);
dfs_ZXTree(1, -1);
for(int i = 0; i < q; i++) {
int l, r, k; scanf("%d%d%d", &l, &r, &k);
quest[i].l = l; quest[i].r = r; quest[i].k = k;
query[l].push_back(r); query[r].push_back(l);
num[l].push_back(i); num[r].push_back(i);
}
fa[1] = T[0];
dfs_lca(1);
for(int i = 0; i < q; i++) {
printf("%d\n", t[Query(T[quest[i].l], T[quest[i].r], lca[i], quest[i].k)]);
}
}
return 0;
}
SPOJ 10628 Count on a tree (lca+主席树)的更多相关文章
- BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )
Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...
- BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 5217 Solved: 1233 ...
- bzoj 2588 Spoj 10628. Count on a tree(主席树)
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- bzoj 2588: Spoj 10628. Count on a tree【主席树+倍增】
算是板子,把值离散化,每个点到跟上做主席树,然后查询的时候主席树上用u+v-lca-fa[lca]的值二分 #include<iostream> #include<cstdio> ...
- 【bzoj2588】Spoj 10628. Count on a tree 离散化+主席树
题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个 ...
- [BZOJ2588]Count on a tree(LCA+主席树)
题面 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问 ...
- 【bzoj2588/P2633】count on a tree —— LCA + 主席树
(以下是luogu题面) 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问 ...
- Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 2588: Spoj 10628. Count on a tree Time Limit ...
- 【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA
[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lasta ...
- Bzoj 2588 Spoj 10628. Count on a tree(树链剖分LCA+主席树)
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MB Description 给定一棵N个节点的树,每个点 ...
随机推荐
- docker(一):docker是什么?
认识容器:docker入门篇 docker是什么? Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚 ...
- [Luogu2324]八数码难题
抱歉...我可能真的做搜索上瘾了... 还是IDA*,自己看看就好了... 注意一下搜索顺序 #include<cstdio> #include<queue> #include ...
- [BZOJ2017][Usaco2009 Nov]硬币游戏(要复习系列)
又是DP? 好吧,或者说是博弈论,但是我不会啊. 先搞个O(n^3)的记忆化搜索,然后瞎搞好像发现两个状态几乎一样? 竟然过了样例,然后竟然A了... #include<iostream> ...
- ACM_一道耗时间的水题
一道耗时间的水题 Time Limit: 2000/1000ms (Java/Others) Problem Description: Do you know how to read the phon ...
- animation与transition的简单讲述
CSS动画分为两大组成部分:transition和animation 在CSS 3引入Transition(过渡)这个概念之前,CSS是没有时间轴的.也就是说,所有的状态变化,都是即时完成. tran ...
- 复习java基础第一天
一:static static: 静态的. 1. 若需要一个类的多个对象共享一个变量,则该变量需要使用 static 修饰. 2. 因为 static 修饰的变量为类的所有的实例所共享,所以 ...
- **ML : ML中的最优化方法
前言: 在机器学习方法中,若模型理解为决策模型,有些模型可以使用解析方法.不过更一般的对模型的求解使用优化的方法,更多的数据可以得到更多的精度. AI中基于归纳的方法延 ...
- (转)基于openlayers实现聚类统计展示
http://blog.csdn.net/gisshixisheng/article/details/46137015 概述: 在前面的博文中讲述过基于Arcgis for js如何实现聚类统计展示, ...
- CorelDRAW2019新耀发布会,报名即可领红包!
30年时光荏苒!眨眼风惊雨过. 在1989年的春天,CorelDRAW 1.0正式发布,一经面世就掀起了图形设计行业革命浪潮,这个图形工具不仅给设计师提供了矢量图像.页面设计,更能应用于网站制作.位 ...
- scrapy-redis使redis不止保存url
先看scrapy-redis源码 class RedisMixin(object): """Mixin class to implement reading urls f ...