【BZOJ2588】Spoj 10628. Count on a tree

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

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

题解:先树剖求出LCA,然后再树上搞一个主席树,第i棵线段树保存的是从根到i的路径上的所有点,然后查询的时候就在用a的线段树+b的线段树-lca(a,b)的线段树-fa(lca(a,b))的线段树就行了。

主席树写的还是不熟练,注意在建树的时候一定要按着DFS序建。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100010;
struct NUM
{
int num,org;
}v[maxn];
struct NODE
{
int siz,ls,rs;
}s[maxn*40];
int n,m,tot,nm,ans,cnt;
int ref[maxn],root[maxn],q[maxn];
int fa[maxn],size[maxn],top[maxn],son[maxn],deep[maxn],to[maxn<<1],next[maxn<<1],head[maxn];
bool cmp1(NUM a,NUM b)
{
return a.num<b.num;
}
bool cmp2(NUM a,NUM b)
{
return a.org<b.org;
}
void add(int a,int b)
{
to[cnt]=b;
next[cnt]=head[a];
head[a]=cnt++;
}
void dfs1(int x)
{
size[x]=1;
for(int i=head[x];i!=-1;i=next[i])
{
if(to[i]!=fa[x])
{
fa[to[i]]=x,deep[to[i]]=deep[x]+1;
dfs1(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>size[son[x]]) son[x]=to[i];
}
}
}
void dfs2(int x,int tp)
{
top[x]=tp;
q[++q[0]]=x;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=next[i])
if(to[i]!=fa[x]&&to[i]!=son[x])
dfs2(to[i],to[i]);
}
void insert(int x,int &y,int l,int r,int p)
{
y=++tot;
if(l==r)
{
s[y].siz=s[x].siz+1;
return ;
}
int mid=l+r>>1;
if(p<=mid) s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,p);
else s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,p);
s[y].siz=s[s[y].ls].siz+s[s[y].rs].siz;
}
void query(int a,int b,int c,int d,int l,int r,int p)
{
if(l==r)
{
ans=ref[l];
return ;
}
int mid=l+r>>1;
if(s[s[a].ls].siz+s[s[b].ls].siz-s[s[c].ls].siz-s[s[d].ls].siz>=p) query(s[a].ls,s[b].ls,s[c].ls,s[d].ls,l,mid,p);
else query(s[a].rs,s[b].rs,s[c].rs,s[d].rs,mid+1,r,p-s[s[a].ls].siz-s[s[b].ls].siz+s[s[c].ls].siz+s[s[d].ls].siz);
}
int getlca(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]>deep[top[y]]) x=fa[top[x]];
else y=fa[top[y]];
}
if(deep[x]<deep[y]) return x;
return y;
}
int readin()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=readin(),m=readin();
memset(head,-1,sizeof(head));
int i,a,b,c,d,e;
for(i=1;i<=n;i++) v[i].num=readin(),v[i].org=i;
sort(v+1,v+n+1,cmp1);
ref[nm]=-1;
for(i=1;i<=n;i++)
{
if(v[i].num>ref[nm]) ref[++nm]=v[i].num;
v[i].num=nm;
}
sort(v+1,v+n+1,cmp2);
for(i=1;i<n;i++)
{
a=readin(),b=readin();
add(a,b),add(b,a);
}
deep[1]=1,dfs1(1),dfs2(1,1);
for(i=1;i<=n;i++) insert(root[fa[q[i]]],root[q[i]],1,nm,v[q[i]].num);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&e);
a^=ans;
int c=getlca(a,b),d=fa[c];
query(root[a],root[b],root[c],root[d],1,nm,e);
printf("%d",ans);
if(i!=m) printf("\n");
}
return 0;
}

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA的更多相关文章

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

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

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

  3. spoj COT - Count on a tree(主席树 +lca,树上第K大)

    您将获得一个包含N个节点的树.树节点的编号从1到Ñ.每个节点都有一个整数权重. 我们会要求您执行以下操作: uvk:询问从节点u到节点v的路径上的第k个最小权重 输入 在第一行中有两个整数Ñ和中号.( ...

  4. spoj cot: Count on a tree 主席树

    10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...

  5. 【主席树】bzoj2588 Spoj 10628. Count on a tree

    每个点的主席树的root是从其父转移来的.询问的时候用U+V-LCA-FA(LCA)即可. #include<cstdio> #include<algorithm> using ...

  6. BZOJ2588: Spoj 10628. Count on a tree

    传送门 刚开始看错题以为是dfs序瞎搞.. 后来看清题了开始想用树剖瞎搞... 感觉要滚粗啊.. 对于每个点到根的路径建立线段树,暴力建MLE没跑,上主席树,然后$(x,y)$的路径就可以先求出来$L ...

  7. SPOJ Count on a tree(主席树+LCA)

    一.题目 COT - Count on a tree You are given a tree with N nodes. The tree nodes are numbered from 1 to  ...

  8. [bzoj2588][count on a tree] (主席树+lca)

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

  9. bzoj2588: Spoj 10628. Count on a tree(树上第k大)(主席树)

    每个节点继承父节点的树,则答案为query(root[x]+root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]) #include<iostream> #i ...

随机推荐

  1. java判断邮件是否发送成功

    http://www.cnblogs.com/winner-0715/p/5136392.html

  2. MongoDB自动删除过期数据--TTL索引

      前序: 由于公司业务需求,对于3个月前的过期数据需要进行删除动作,以释放空间和方便维护 本来想的是使用crontab写个脚本定时执行,但是看到Mongo本身就有自动删除过期数据的功能,所以还是用一 ...

  3. 开源图形数据库Neo4j使用 php开发

    先看看它的示例数据 打开 Neo4j Browser :play movie graph 写代码,然后点play执行 Cypher, the graph query language.Neo4j提供了 ...

  4. 看板与Scrum:哪个更适合你的团队?

    敏捷是理想型指标和原则,看板和Scrum是帮助团队坚持敏捷原则并完成工作的基本框架.本文详细介绍了在Scrum和看板之间做出选择时要考虑的关键因素,以及如果我们无法做出决定时该怎么办. Scrum和看 ...

  5. rails rake和示例

    一篇看到的讲解得不错的文章 http://blog.csdn.net/clskkk2222/article/details/6735365 这里还有一些例子: Rake Documentation R ...

  6. 当数据库的字段为date类型时候

    当数据库的字段为date类型时候: //--------------------------------------------------数据库设计------------------------- ...

  7. BOOTH 算法的简单理解

    学习FPGA时,对于乘法的运算,尤其是对于有符号的乘法运算,也许最熟悉不过的就是 BOOTH算法了. 这里讲解一下BOOTH算法的计算过程,方便大家对BOOTH的理解.        上图是BOOTH ...

  8. DM816x算法具体解释--之OSD

    简单介绍: 本文介绍DM8168 DVRRDK中传入DSP内部的视频格式以及大概的处理流程. 背景: 可能有非常多人为了加快研发的速度.减少难度,选择在DVRRDk已有的OSD内加入自己的DSP算法. ...

  9. CentOS系统安装后的基础优化

    在运维工作中,我们发现Linux系统安装之后并不能立即投入生产环境使用,往往需要先经过我们运维人员的优化才行. 下面我就为大家简单讲解几点关于Linux系统安装后的基础优化操作. 注意:本次优化都是基 ...

  10. IFrame实现的无刷新(仿ajax效果)...

    前台代码: <iframe style="display:none;" name="gg"></iframe> <form act ...