Description

给定一棵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

HINT:
N,M<=100000
暴力自重。。。

【题意】

求u到v路径上的第k小的数。

【思路】

主席树,dfs序,lca,二分

主席树就是可持久化线段树,即保留历史版本的线段树。

为什么要保留历史版本呢?因为我们要完成对区间的查询,对于一个区间和的询问我们可以利用前缀和的思想来解决,主席树大概也是这个思路。

我们对每一个点建一棵线段树,每一棵线段树以权值为下标,维护区间中点的数目。依次建立每一棵线段树,第i棵线段树是从第i-1棵线段树上插了个权值i而得到的。这样对于区间[l,r]的查询,我们可以通过询问T[r]和T[l-1]的相应区间而得到。

对应到这道题中,我们先离散化权值(不离散化空间还不得飞起来233),然后按照树的形态来建立每一棵线段树,每一棵线段树就是从父节点对应的线段树上拓展来的,相当于上一个版本。这样从祖先到结点路径上的线段树就是逐渐增大且只包括路径上的权值的。

建好主席树后,对于查询(u,v),二分数的大小mid,我们就可以知道“区间”内所有小于mid的数目,为T[u].lc.sum-T[lca].lc.sum+T[v].lc.sum-T[fa[lca]].lc.sum (T[i]为i对应一棵线段树,lc为左儿子,sum为对应的权值数目),如果rank比之小则缩小数的区间,使u,v,lca,fa[lca]进入左儿子,否则修改rank后进入右儿子。

【代码】

 #include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
const int N = 1e5+;
const int M = *1e6+;
const int D = ; int n,m,tot,sz,ind;
int hash[N],pos[N],num[N],v[N],root[N];
int sum[M],ls[M],rs[M];
vector<int> g[N]; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-')f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'', c=getchar();
return x*f;
}
int fa[N],top[N],son[N],siz[N],dep[N];
void dfs1(int u)
{
siz[u]=; son[u]=; num[++ind]=u; pos[u]=ind;
for(int i=;i<g[u].size();i++) {
int v=g[u][i];
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=;i<g[u].size();i++) {
int v=g[u][i];
if(v!=fa[u] && v!=son[u]) dfs2(v,v);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]>dep[v]? v:u;
}
void update(int l,int r,int x,int &y,int num)
{
y=++sz;
sum[y]=sum[x]+;
if(l==r) return ;
ls[y]=ls[x] ; rs[y]=rs[x];
int mid=(l+r)>>;
if(num<=mid) update(l,mid,ls[x],ls[y],num);
else update(mid+,r,rs[x],rs[y],num);
}
int query(int x,int y,int rank)
{
int a=x,b=y,c=lca(x,y),d=fa[c];
a=root[pos[a]],b=root[pos[b]],c=root[pos[c]],d=root[pos[d]];
int l=,r=tot;
while(l<r) {
int mid=(l+r)>>;
int now=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]];
if(rank<=now) r=mid,a=ls[a],b=ls[b],c=ls[c],d=ls[d];
else l=mid+,rank-=now,a=rs[a],b=rs[b],c=rs[c],d=rs[d];
}
return hash[l];
} int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
n=read(),m=read();
FOR(i,,n) {
v[i]=read(); hash[i]=v[i];
}
sort(hash+,hash+n+);
tot=;
FOR(i,,n) if(hash[i]!=hash[i-])
hash[++tot]=hash[i];
FOR(i,,n)
v[i]=lower_bound(hash+,hash+tot+,v[i])-hash;
int x,y,z;
FOR(i,,n-) {
x=read(),y=read();
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(),dfs2(,);
FOR(i,,n) {
int t=num[i];
update(,tot,root[pos[fa[t]]],root[i],v[t]);
}
int lastans=;
FOR(i,,m) {
x=read(),y=read(),z=read();
x^=lastans;
printf("%d",lastans=query(x,y,z));
if(i!=m) puts("");
}
return ;
}

bzoj 2588 Spoj 10628. Count on a tree(主席树)的更多相关文章

  1. 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 ...

  2. BZOJ 2588: Spoj 10628. Count on a tree 主席树+lca

    分析:树上第k小,然后我想说的是主席树并不局限于线性表 详细分析请看http://www.cnblogs.com/rausen/p/4006116.html,讲的很好, 然后因为这个熟悉了主席树,真是 ...

  3. 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 ...

  4. BZOJ 2588: Spoj 10628. Count on a tree 树上跑主席树

    2588: Spoj 10628. Count on a tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/J ...

  5. BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )

    Orz..跑得还挺快的#10 自从会树链剖分后LCA就没写过倍增了... 这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树 ----------------------- ...

  6. 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个节点的树,每个点 ...

  7. bzoj 2588 Spoj 10628. Count on a tree (可持久化线段树)

    Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 7669  Solved: 1894[Submi ...

  8. 【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

    [BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lasta ...

  9. 主席树 || 可持久化线段树 || LCA || BZOJ 2588: Spoj 10628. Count on a tree || Luogu P2633 Count on a tree

    题面: Count on a tree 题解: 主席树维护每个节点到根节点的权值出现次数,大体和主席树典型做法差不多,对于询问(X,Y),答案要计算ans(X)+ans(Y)-ans(LCA(X,Y) ...

  10. ●BZOJ 2588 Spoj 10628. Count on a tree

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2588 题解: 主席树,在线,(求LCA)感觉主席树真的好厉害...在原树上建主席树.即对于原 ...

随机推荐

  1. 【莫比乌斯反演】关于Mobius反演与gcd的一些关系与问题简化(bzoj 2301 Problem b&&bzoj 2820 YY的GCD&&BZOJ 3529 数表)

    首先我们来看一道题  BZOJ 2301 Problem b Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd( ...

  2. [转载]VS2012程序打包部署详解

    上篇博客把收费系统的总体设计进行了一遍讲解,讲解的同时掺杂了些有关.NET编译机制的总结.程序编写测试完成后接下来我们要做的是打包部署程序,但VS2012让人心痛的是没有了打包工具.不知道出于什么原因 ...

  3. [转载]C#缓存absoluteExpiration、slidingExpiration两个参数的疑惑

    看了很多资料终于搞明白cache中absoluteExpiration,slidingExpiration这两个参数的含义. absoluteExpiration:用于设置绝对过期时间,它表示只要时间 ...

  4. hdu 4649 Professor Tian 反状态压缩+概率DP

    思路:反状态压缩——把数据转换成20位的01来进行运算 因为只有20位,而且&,|,^都不会进位,那么一位一位地看,每一位不是0就是1,这样求出每一位是1的概率,再乘以该位的十进制数,累加,就 ...

  5. http://www.linuxidc.com/Linux/2007-09/7399.htm

    http://www.linuxidc.com/Linux/2007-09/7399.htm

  6. C++中 模板Template的使用

    1.在c++Template中很多地方都用到了typename与class这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢?答:class用于定义类,在模板引入c++后,最初定义模板的方法 ...

  7. 200. Number of Islands

    题目: Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is s ...

  8. 隐马尔科夫模型,第三种问题解法,维比特算法(biterbi) algorithm python代码

    上篇介绍了隐马尔科夫模型 本文给出关于问题3解决方法,并给出一个例子的python代码 回顾上文,问题3是什么, 下面给出,维比特算法(biterbi) algorithm 下面通过一个具体例子,来说 ...

  9. Complete The Pattern #6 - Odd Ladder

    Complete The Pattern #6 - Odd Ladder Task: You have to write a function pattern which creates the fo ...

  10. 谈谈javascript插件的写法

    插件顾名思义就是能在一个页面多处使用, 各自按自己的参数配置运行, 并且相互不会冲突. 会写javascript插件是进阶js高级的必经之路, 也是自己所学知识的一个典型的综合运用. 如果你还没头绪, ...