点此看题面

大致题意: 给你一棵树,每次问你两点之间第\(k\)小的点权,强制在线。

主席树

这种题目强制在线一般就是数据结构了。

而看到区间第\(k\)小,很容易就能想到主席树

至少不会有人想到树套树

树上主席树

与一般的主席树不同,这题的主席树是树上主席树(不过许多奆佬称其为主席树上树)。

维护数列的主席树,我们一般是由前一个数的主席树构造当前树的主席树。

而树上的主席树其实也是类似的,可以由父亲节点的主席树构造当前树的主席树。

关于查询操作

关于查询两个节点\(x,y\)路径间第\(k\)小的权值,我们进行如下操作:

  • 首先,找到\(x\)和\(y\)的\(LCA\),姑且命名它为\(z\)。
  • 然后,我们可以进行差分,即用\(x\)和\(y\)的值与\(z\)和\(fa_z\)的值相减,就可以得出最终的答案(这与数组版的主席树是类似的)。

对于\(LCA\),我们可以直接用倍增\(LCA\)

然后我们就可以发现这是一道主席树板子题。

代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define uint unsigned int
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define abs(x) ((x)<0?-(x):(x))
#define INF 1e9
#define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
#define ten(x) (((x)<<3)+((x)<<1))
#define N 100000
#define LogN 20
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,cnt,ee=0,a[N+5],p[N+5],lnk[N+5],Depth[N+5],fa[N+5][LogN+5];
struct edge
{
int to,nxt;
}e[(N<<1)+5];
class FIO
{
private:
#define Fsize 100000
#define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
public:
FIO() {FinNow=FinEnd=Fin;}
inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;}
inline void read_char(char &x) {while(isspace(x=tc()));}
inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
inline void write_char(char x) {pc(x);}
inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
inline void end() {fwrite(Fout,1,FoutSize,stdout);}
}F;
inline int LCA(int x,int y)//倍增LCA
{
register int i;
if(Depth[x]<Depth[y]) swap(x,y);
for(i=0;Depth[x]^Depth[y];++i) if((Depth[x]^Depth[y])&(1<<i)) x=fa[x][i];
if(!(x^y)) return x;
for(i=0;fa[x][i]^fa[y][i];++i);
for(--i;i>=0;--i) if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
class Class_ChairmanTree//主席树
{
private:
int n,tot,Root[N+5];
struct Tree
{
int Val,Size,Son[2];
}node[N*LogN+5];
inline void Build(int l,int r,int &rt)//建树
{
if(!rt&&(rt=++tot),!(l^r)) return;
register int mid=l+r>>1;
Build(l,mid,node[rt].Son[0]),Build(mid+1,r,node[rt].Son[1]);
}
inline void ins(int l,int r,int &rt,int lst,int val)//插入
{
if(node[rt=++tot]=node[lst],++node[rt].Size,!(l^r)) return;
register int mid=l+r>>1;
val<=mid?ins(l,mid,node[rt].Son[0],node[lst].Son[0],val):ins(mid+1,r,node[rt].Son[1],node[lst].Son[1],val);
}
inline int qry(int l,int r,int rt1,int rt2,int rt3,int rt4,int k)//查询
{
if(!(l^r)) return l;
register int mid=l+r>>1,t=node[node[rt3].Son[0]].Size+node[node[rt4].Son[0]].Size-node[node[rt1].Son[0]].Size-node[node[rt2].Son[0]].Size;
if(t>=k) return qry(l,mid,node[rt1].Son[0],node[rt2].Son[0],node[rt3].Son[0],node[rt4].Son[0],k);
else return qry(mid+1,r,node[rt1].Son[1],node[rt2].Son[1],node[rt3].Son[1],node[rt4].Son[1],k-t);
}
public:
inline void Init(int len) {Build(1,n=len,Root[0]);}//初始化
inline void Insert(int v,int nv,int val) {ins(1,n,Root[nv],Root[v],val);}
inline int Query(int v1,int v2,int k) {return qry(1,n,Root[LCA(v1,v2)],Root[fa[LCA(v1,v2)][0]],Root[v1],Root[v2],k);}
}ChairmanTree;
inline int find(int x)//离散化
{
register int l=1,r=cnt,mid=l+r>>1;
for(;l<=r;mid=l+r>>1) p[mid]<x?l=mid+1:r=mid-1;
return l;
}
inline void Init(int x)//初始化
{
register int i;
for(ChairmanTree.Insert(fa[x][0],x,find(a[x])),i=1;i<=LogN;++i) fa[x][i]=fa[fa[x][i-1]][i-1];//由父亲的主席树建树
for(i=lnk[x];i;i=e[i].nxt) if(fa[x][0]^e[i].to) Depth[e[i].to]=Depth[x]+1,fa[e[i].to][0]=x,Init(e[i].to);//继续遍历
}
int main()
{
register int i,x,y,z,s,Q,ans=0;
for(F.read(n),F.read(Q),i=1;i<=n;++i) F.read(a[i]),p[i]=a[i];
for(i=1;i<n;++i) F.read(x),F.read(y),add(x,y),add(y,x);
for(sort(p+1,p+n+1),ChairmanTree.Init(cnt=unique(p+1,p+n+1)-p-1),Init(1);Q;--Q)
F.read(x),F.read(y),F.read(z),F.write(ans=p[ChairmanTree.Query(x^ans,y,z)]),F.write_char('\n');//求答案
return F.end(),0;
}

【洛谷2633】Count on a tree(树上主席树)的更多相关文章

  1. 洛谷P2633 Count on a tree(主席树,倍增LCA,树上差分)

    洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...

  2. 洛谷P2633 Count on a tree(主席树,倍增LCA)

    洛谷题目传送门 题目大意 就是给你一棵树,每个点都有点权,每次任意询问两点间路径上点权第k小的值(强制在线). 思路分析 第k小......又是主席树了.但这次变成树了,无法直接维护前缀和. 又是树上 ...

  3. Count on a tree 树上主席树

    Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...

  4. 解题:洛谷2633 Count on a tree

    题面 在树上建主席树...... 每个点从父亲那里建过来,最后建出来就是从根到$i$这条链上的主席树,查询的时候一边差分一边查询 ($cmt[u]+cmt[v]-cmt[lca(u,v)]-cmt[a ...

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

  6. 【BZOJ2588】Count On a Tree(主席树)

    [BZOJ2588]Count On a Tree(主席树) 题面 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第 ...

  7. ☆ [洛谷P2633] Count on a tree 「树上主席树」

    题目类型:主席树+\(LCA\) 传送门:>Here< 题意:给出一棵树.每个节点有点权.问某一条路径上排名第\(K\)小的点权是多少 解题思路 类似区间第\(K\)小,但放在了树上. 考 ...

  8. 【洛谷 P2633】 Count on a tree(主席树,树上差分)

    题目链接 思维难度0 实现难度7 建出主席树后用两点的状态减去lca和lca父亲的状态,然后在新树上跑第\(k\)小 #include <cstdio> #include <cstr ...

  9. 洛谷 P2633 Count on a tree

    P2633 Count on a tree 题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中last ...

  10. 洛谷 P6177 - Count on a tree II/【模板】树分块(树分块)

    洛谷题面传送门 好家伙,在做这道题之前我甚至不知道有个东西叫树分块 树分块,说白了就是像对序列分块一样设一个阈值 \(B\),然后在树上随机撒 \(\dfrac{n}{B}\) 个关键点,满足任意一个 ...

随机推荐

  1. 51nod1305(简单逻辑)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1305 题意:中文题诶- 思路:1e5的数据直接暴力肯定是不行 ...

  2. SpringBoot2.0 基础案例(04):定时任务和异步任务的使用方式

    一.定时任务 1.基本概念 按照指定时间执行的程序. 2.使用场景 数据分析 数据清理 系统服务监控 二.同步和异步 1.基本概念 同步调用 程序按照代码顺序依次执行,每一行程序都必须等待上一行程序执 ...

  3. JMETER进行REST API测试(分步指南)

    我确定你在这里是因为你需要加载测试Json Rest API.这并不奇怪,因为Rest API现在越来越受欢迎. 这本指南的目的:帮助您进行负载测试一个Json的 REST API 通过一个具体的例子 ...

  4. HTTP的一些理解

    URI是Uniform Resource Identifier的缩写,统一资源标识符.URI用字符串标识某一互联网资源,而URL标识资源的地点(互联网上所处的位置).可见URL是URI的子集. 典型的 ...

  5. 3、python数据类型之字符串(str)

    字符串是任何计算机语言中最常见的数据类型,python中也不例外,因此熟练掌握字符串是学习python的必备技能.python中字符串三种定义方式 str = 'wang' str = "w ...

  6. java运行环境和配置环境

    1.配置JAVA_HOME,CLASSPATH,PATH的意义 JAVA_HOME:指向jdk的安装目录,意义不多说. PATH:作用是指向javac编译器,将java编译成 .class文件. CL ...

  7. springcloud中常用的注解@

    @SpringBootApplication是springboot启动类,包括三个注解,他们的作用分别是: @Configuration:表示将该类作用springboot配置文件类 @EnableA ...

  8. Ubuntu批量修改文件后缀

    rename 's/\.JPG/.jpg/' *.JPG 把JPG后缀改为jpg 参考url====http://blog.csdn.net/whuslei/article/details/67249 ...

  9. (转)diff 命令

    每天一个linux命令(36):diff 命令  原文:http://www.cnblogs.com/peida/archive/2012/12/12/2814048.html diff 命令是 li ...

  10. VMWare复制虚拟机系统后,模块“Disk”无法启动【转】

    1.找到虚拟机所在的目录 将 .vmx文件打开 将文件vmci0.present = "TRUE" 改为 vmci0.present = "FALSE" 2.删 ...