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\)行,表示每个询问的答案。


一看是无修改的第\(k\)值查询,我们可以用可持久化降维。

就是把序列上的第\(k\)值扩展到了树上。

我们考虑一条树上路径可以被怎么表示

这样类比,假设树上每个点有点权,则树上路径点权之和可以被树的前缀和数组这样表示

\(len(u,v)=dis[u]+dis[v]-dis[lca(u,v)]-dis[father(lca[u,v])]\)

然而前缀和其实就是一维的可持久化,我们把\(dis\)数组类比成主席树加加减减就好了


Code:

#include <cstdio>
#include <algorithm>
#define ls ch[now][0]
#define rs ch[now][1]
const int N=100010;
int Next[N<<1],to[N<<1],head[N],cnt;
void add(int u,int v)
{
Next[++cnt]=head[u];to[cnt]=v;head[u]=cnt;
}
int sum[N*25],ch[N*25][2],tot,n,m,n_;
void updata(int now)
{
sum[now]=sum[ls]+sum[rs];
}
int rebuild(int las,int l,int r,int pos)
{
int now=++tot;
if(l==r)
{
sum[now]=sum[las]+1;
return now;
}
int mid=l+r>>1;
if(pos<=mid)
{
ls=rebuild(ch[las][0],l,mid,pos);
rs=ch[las][1];
}
else
{
ls=ch[las][0];
rs=rebuild(ch[las][1],mid+1,r,pos);
}
updata(now);
return now;
}
int ha[N],loc[N],root[N];
int query(int u,int v,int lca,int lcaf,int l,int r,int k)
{
if(l==r) return ha[l];
int s=sum[ch[u][0]]+sum[ch[v][0]]-sum[ch[lca][0]]-sum[ch[lcaf][0]];
int mid=l+r>>1;
if(k<=s) return query(ch[u][0],ch[v][0],ch[lca][0],ch[lcaf][0],l,mid,k);
else return query(ch[u][1],ch[v][1],ch[lca][1],ch[lcaf][1],mid+1,r,k-s);
}
int top[N],dfn[N],f[N],dep[N],ws[N],siz[N],time;
void dfs1(int now)
{
root[now]=rebuild(root[f[now]],1,n,loc[now]);
siz[now]++;
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(v!=f[now])
{
f[v]=now;
dep[v]=dep[now]+1;
dfs1(v);
siz[now]+=siz[v];
if(siz[ws[now]]<siz[v])
ws[now]=v;
}
}
}
void dfs2(int now,int anc)
{
dfn[now]=++time;
top[now]=anc;
if(ws[now]) dfs2(ws[now],anc);
for(int i=head[now];i;i=Next[i])
if(!dfn[to[i]])
dfs2(to[i],to[i]);
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
x=f[top[x]];
else
y=f[top[y]];
}
return dep[x]<dep[y]?x:y;
}
std::pair <int,int > node[N];
void init()
{
scanf("%d%d",&n_,&m);
for(int d,i=1;i<=n_;i++)
{
scanf("%d",&d);
node[i]=std::make_pair(d,i);
}
std::sort(node+1,node+1+n_);
for(int i=1;i<=n_;i++)
{
if(node[i].first!=node[i-1].first) n++;
ha[n]=node[i].first;
loc[node[i].second]=n;
}
for(int u,v,i=1;i<n_;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1);
dfs2(1,1);
}
void work()
{
for(int u,v,lca,k,lastans=0,i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&k);
u^=lastans;
lca=LCA(u,v);
printf("%d\n",lastans=query(root[u],root[v],root[lca],root[f[lca]],1,n,k));
}
}
int main()
{
init();
work();
return 0;
}

2018.7.31

bzoj 2588 Count on a tree 解题报告的更多相关文章

  1. BZOJ 2588 Count on a tree (COT) 是持久的段树

    标题效果:两棵树之间的首次查询k大点的权利. 思维:树木覆盖树,事实上,它是正常的树木覆盖了持久段树. 由于使用权值段树可以寻求区间k大,然后应用到持久段树思想,间隔可以做减法.详见代码. CODE: ...

  2. BZOJ.2588.Count on a tree(主席树 静态树上第k小)

    题目链接 /* 序列上的主席树 某点是利用前一个点的根建树 同理 树上的主席树 某个节点可以利用其父节点(is unique)的根建树 排名可以利用树上前缀和求得: 对于(u,v),w=LCA(u,v ...

  3. bzoj 2588 Count on a tree

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

  4. 【LeetCode】863. All Nodes Distance K in Binary Tree 解题报告(Python)

    [LeetCode]863. All Nodes Distance K in Binary Tree 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...

  5. 【LeetCode】297. Serialize and Deserialize Binary Tree 解题报告(Python)

    [LeetCode]297. Serialize and Deserialize Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode ...

  6. 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)

    [LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  7. 【LeetCode】109. Convert Sorted List to Binary Search Tree 解题报告(Python)

    [LeetCode]109. Convert Sorted List to Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id ...

  8. 【LeetCode】236. Lowest Common Ancestor of a Binary Tree 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  9. 【LeetCode】99. Recover Binary Search Tree 解题报告(Python)

    [LeetCode]99. Recover Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/p ...

随机推荐

  1. “腾讯WeTest助力《龙珠直播》盘点APP质量问题”

    WeTest 导读 据调查数据表明,移动端用户在使用APP时如果遇到了闪退等兼容性问题,20%的用户会选择直接卸载. 2016年,被称为中国直播元年.随着各类直播平台的疯狂生长与扩散,直播产品在内容, ...

  2. 「日常训练」Case of Matryoshkas(Codeforces Round #310 Div. 2 C)

    题意与分析(CodeForces 556C) 为了将所有\(n\)个娃娃编号递增地串在一起(原先是若干个串,每个串是递增的), 我们有两种操作: 拆出当前串中最大编号的娃娃(且一定是最右边的娃娃). ...

  3. Linux命令应用大词典-第39章 网络安全

    39.1 rtacct:网络统计工具 39.2 nmap:报告远程主机特征 39.3 tcpdump:实现网络数据采集分析 39.4 iptstate:显示IP表状态表条目 39.5 nstat:监控 ...

  4. mapReduce入门教程

    什么是MapReduce MapReduce是Google提出的一个软件架构,用于大规模数据集(大于1TB)的并行运算.概念"Map(映射)"和"Reduce(归纳)&q ...

  5. 购物单:Excel的应用

    题目描述: 小明刚刚找到工作,老板人很好,只是老板夫人很爱购物.老板忙的时候经常让小明帮忙到商场代为购物.小明很厌烦,但又不好推辞. 这不,XX大促销又来了!老板夫人开出了长长的购物单,都是有打折优惠 ...

  6. LeetCode - 136. Single Number - ( C++ ) - 解题报告 - 位运算思路 xor

    1.题目大意 Given an array of integers, every element appears twice except for one. Find that single one. ...

  7. java面试整理

    IO和NIO的区别 这是一个很常见的问题,如果单纯的只回答IO和NIO的区别,只能算及格.我个人觉得应该从以下几个方面回答: 1).IO简介, 2).TCP的三次握手,因为这也是两者的区别之一, 3) ...

  8. 将HTML页面页脚固定在页面底部(多种方法实现)

    当一个HTML页面中含有较少的内容时,Web页面的footer部分随着飘上来,处在页面的半腰中间,给视觉效果带来极大的影响,接下来为大家介绍下如何将页脚固定在页面底部,感兴趣的朋友可以了解下 作为一个 ...

  9. 适合初学者的嵌入式Linux计划

    俗话说万事开头难,刚开始的时候,你是否根本就不知如何开始,上网查资料被一堆堆新名词搞的找不到北,去图书馆看书也是找不到方向?又是arm,又是linux,又是uboot头都大了,不知道自己究竟从哪里开始 ...

  10. Thrift IDL使用方式

    I.背景 众所周知,Thrift是一个RPC的框架,其可用于不同语言之间的服务相互调用.比如最近接触到的一个运用环境: *前端使用Node.Js重构了部分我们的老旧代码(前后端未分离的SpringBo ...