BZOJ2588 SPOJ10628 Count on a tree 【主席树】
BZOJ2588 Count on a tree
题目描述
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
输入格式:
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
输出格式:
M行,表示每个询问的答案。
输入样例:
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
输出样例:
2
8
9
105
7
说明
N,M<=100000
一道不错(毒瘤)的主席树练习题,因为主席树保存的是前缀和,这道题的题目框架是树形的,所以我们把一般的线性关系的主席树变成树形关系,再进行权值线段树的持久化就可以了。又因为对于两个节点(u,v)" role="presentation">(u,v)(u,v),u到v路径上的数字个数可以表示成siz[u]+siz[v]−siz[lca(u,v)]−siz[fa[lca(u,v)]]" role="presentation">siz[u]+siz[v]−siz[lca(u,v)]−siz[fa[lca(u,v)]]siz[u]+siz[v]−siz[lca(u,v)]−siz[fa[lca(u,v)]],根据这个性质我们就可以进行权值线段树上的二分了,注意书写细节即可(数组开小了)。
/*dream_maker*/
#include<bits/stdc++.h>
using namespace std;
#define N 200010
#define M 2000010
int read(){
int ans=0,w=1;char c=getchar();
while(c!='-'&&!isdigit(c))c=getchar();
if(c=='-')w=-1,c=getchar();
while(isdigit(c))ans=ans*10+c-'0',c=getchar();
return ans*w;
}
int n,m,s,lastans=0,u,v,tot,cnt;
struct Edge{int v,next;}E[N<<1];
int head[N],a[N],b[N],fa[N][32],dep[N];
int rt[M]={0},ls[M]={0},rs[M]={0},siz[M]={0};
void add(int u,int v){
E[++tot]=(Edge){v,head[u]};
head[u]=tot;
}
void build(int &rt,int l,int r){
if(l>r)return;
rt=++cnt;
if(l==r)return;
int mid=(l+r)>>1;
build(ls[rt],l,mid);
build(rs[rt],mid+1,r);
}
void modify(int &rt,int last,int l,int r,int val){
rt=++cnt;
siz[rt]=siz[last]+1;
ls[rt]=ls[last];
rs[rt]=rs[last];
if(l==r)return;
int mid=(l+r)>>1;
if(mid>=val)modify(ls[rt],ls[last],l,mid,val);
else modify(rs[rt],rs[last],mid+1,r,val);
}
int query(int rt1,int rt2,int rt3,int rt4,int l,int r,int k){
if(l==r)return l;
int mid=(l+r)>>1;
int tmp=siz[ls[rt1]]+siz[ls[rt2]]-siz[ls[rt3]]-siz[ls[rt4]];
if(tmp>=k)return query(ls[rt1],ls[rt2],ls[rt3],ls[rt4],l,mid,k);
else return query(rs[rt1],rs[rt2],rs[rt3],rs[rt4],mid+1,r,k-tmp);
}
void dfs(int u,int f){
fa[u][0]=f;
modify(rt[u],rt[f],1,s,a[u]);
dep[u]=dep[f]+1;
for(int i=head[u];i;i=E[i].next){
int v=E[i].v;
if(v==f)continue;
dfs(v,u);
}
}
int Lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
int t=dep[x]-dep[y];
for(int i=0;i<=31;i++)
if((1<<i)&t)x=fa[x][i];
if(x==y)return x;
for(int i=31;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
// freopen("2588.in","r",stdin);
// freopen("2588.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)b[i]=a[i]=read();
sort(b+1,b+n+1);
s=unique(b+1,b+n+1)-b-1;
for(int i=1;i<n;i++){
u=read();v=read();
add(u,v);add(v,u);
}
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+s+1,a[i])-b;
build(rt[0],1,s);
dfs(1,0);
int up=log2(n)+1;
for(int k=1;k<=up;k++)
for(int i=1;i<=n;i++)
fa[i][k]=fa[fa[i][k-1]][k-1];
for(int i=1;i<=m;i++){
u=read();v=read();int k=read();
u^=lastans;
int lca=Lca(u,v);
int ans=b[query(rt[u],rt[v],rt[lca],rt[fa[lca][0]],1,s,k)];
printf("%d\n",ans);
lastans=ans;
}
return 0;
}
BZOJ2588 SPOJ10628 Count on a tree 【主席树】的更多相关文章
- [bzoj2588][Spoj10628]Count on a tree_主席树
Count on a tree bzoj-2588 Spoj-10628 题目大意:给定一棵n个点的树,m次查询.查询路径上k小值. 注释:$1\le n,m\le 10^5$. 想法:好像更博顺序有 ...
- 【BZOJ-2588】Count on a tree 主席树 + 倍增
2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 3749 Solved: 873[ ...
- 【bzoj2588】Count on a tree 主席树
这题给人开了个新思路. 原本构造一个序列的主席树,是这个位置用上个位置的信息来省空间,树上的主席树是继承父亲的信息来省空间. 此题若带修改怎么办? 若对某个点的权值做修改,则这个点的子树都会受影响,想 ...
- 洛谷P2633/bzoj2588 Count on a tree (主席树)
洛谷P2633/bzoj2588 Count on a tree 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K ...
- 【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA
[BZOJ2588]Spoj 10628. Count on a tree Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lasta ...
- [bzoj2588][count on a tree] (主席树+lca)
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- BZOJ2588:Count on a tree(主席树)
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- 洛谷P2633 Count on a tree(主席树上树)
题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个 ...
- 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 ...
随机推荐
- arm-linux-gcc安装使用教程
arm-linux-gcc如何下载安装2(转) [转]ubuntu下交叉编译环境构建(arm-linux-gcc-3.4.1.tar.bz2 ) 2009-03-03 10:05 1.下载arm-li ...
- bzoj 3039: 玉蟾宫 单调栈或者悬线法求最大子矩阵和
3039: 玉蟾宫 Time Limit: 2 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 有一天,小猫rainbow ...
- CDN方式使用iview
如果没有使用webpack,可以使用我们提供的工具iview-theme来编译 首先需要安装主体生成工具,从npm全局活在项目中局部安装 以全局安装为例: npm install iview-them ...
- 关于localStorage
localStorage 是 HTML5 本地存储的 API,使用键值对的方式进行存取数据,存取的数据只能是字符串.不同浏览器对该 API 支持情况有所差异,如使用方法.最大存储空间等. 使用方法 设 ...
- svn diff color
大致有两种方式: 1,在bashrc中添加如下脚本 svndiff() { svn diff "${@}" | colordiff } 2,修改svn的配置文件 $ vim ~/. ...
- 微信小程序------媒体组件(视频,音乐,图片)
今天主要是简单的讲一下小程序当中的媒体组件,媒体组件包括:视频,音乐,图片等. 先来看看效果图: 1:图片Image <!-- scaleToFill:不保持纵横比缩放图片,使图片的宽高完全拉伸 ...
- Android数据库框架-----GreenDao3的相关使用和版本升级更新
GreenDAO是一款非要流行的Android平台上的数据库框架,性能优秀,代码简洁:是一个将对象映射到SQLite数据库中的轻量且快速的ORM解决方案. GreenDAO 优势 1.一个精简的库 2 ...
- Gruntjs提高生产力(四)
思考: 1.grunt以工程为单位安装插件? 如果有新工程就要重新安装插件或者把安装好的插件拷贝过去.这样很麻烦,解决方案是需要用grunt的项目统一放在grunt项目中. 2.每次需要针对项目编写g ...
- H3C WA2610i-GN FitAP telnet打开
在ac上面:sys_hidecmd 隐藏模式wlan ap ap1 exec-control enable ##目前为disable状态wlan ap ap1 telnet enable ##目前为e ...
- Shell awk文本处理,shell脚本编写
Shell awk文本处理,shell脚本编写 一:内容包含awk.变量.运算符.if多分支 <a>语法糖: awk [options] 'commands' files option - ...