好题,又学两个思路。


先把问题变简单一点,去掉深度限制,那么有两种做法:

  • 经典的前驱后继转化到二维数点。

  • 颜色相同的点按 \(dfs\) 序排序,每个点 \(+1\),相邻两点 \(lca-1\)。转化为区间求和。

第二种相对实现简单。

假如加上深度,我们可以离线问题,按深度顺序加点。

要在线的话,只需要将线段树改为主席树即可。

时间复杂度 \(O(\sum (n+m)\log n)\)。

除了刚才说到的主席树外,本题在实现过程中还需要用到单调栈(记录自己插入时已经插入且颜色相同的前驱后继)。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,M=3e7+5;
int n,tot,low[N],id;
int m,q,dfn[N],a[N];
int tp,sk[N],ij,rt[N];
int t,dep[N],st[N][20];
int fs[N],pr[N],nx[N];
int ls[M],rs[M],sm[M];
vector<int>g[N],cl[N];
int cmp(int x,int y){
return dfn[x]<dfn[y];
}int cmd(int x,int y){
return dep[x]<dep[y];
}int cmb(int x,int y){
return dep[x]!=dep[y]?cmd(x,y):x<y;
}void dfs(int x,int fa){
fs[x]=++ij,dfn[x]=++id;
dep[st[ij][0]=x]=dep[fa]+1;
for(auto y:g[x])
dfs(y,x),st[++ij][0]=x;
low[x]=id;
}int minn(int x,int y){
return dep[x]>dep[y]?y:x;
}void ST(){
for(int i=0;i<19;i++)
for(int j=1;j<=ij-(1<<(i+1))+1;j++)
st[j][i+1]=minn(st[j][i],st[j+(1<<i)][i]);
}int rmq(int l,int r){
int k=log2(r-l+1),x=r-(1<<k)+1;
return minn(st[l][k],st[x][k]);
}int lca(int x,int y){
if(fs[x]>fs[y]) swap(x,y);
return rmq(fs[x],fs[y]);
}void add(int &x,int y,int l,int r,int k,int v){
sm[x=++tot]=sm[y]+v;
if(l==r) return;int mid=(l+r)/2;
if(k<=mid) add(ls[x],ls[y],l,mid,k,v),rs[x]=rs[y];
else add(rs[x],rs[y],mid+1,r,k,v),ls[x]=ls[y];
}int sum(int x,int y,int l,int r,int L,int R){
if(L>R) return 0;
if(L<=l&&r<=R) return sm[x]-sm[y];
int mid=(l+r)/2,re=0;
if(L<=mid) re=sum(ls[x],ls[y],l,mid,L,R);
if(R>mid) re+=sum(rs[x],rs[y],mid+1,r,L,R);
return re;
}void solve(){
for(int i=1;i<=n;i++)
pr[i]=nx[i]=0,g[i].clear(),cl[i].clear();
cin>>n>>q,tot=id=ij=0;int la=0;
for(int i=1,x;i<=n;i++)
cin>>x,a[i]=i,cl[x].push_back(i);
for(int i=2,x;i<=n;i++)
cin>>x,g[x].push_back(i);
dfs(1,0),ST();
sort(a+1,a+n+1,cmd),m=dep[a[n]];
for(int i=1,k;i<=n;i++){
k=cl[i].size(),sort(cl[i].begin(),cl[i].end(),cmp);
for(int j=0;j<k;j++){
while(tp&&cmb(cl[i][j],cl[i][sk[tp]])) tp--;
if(tp) pr[cl[i][j]]=cl[i][sk[tp]];sk[++tp]=j;
}while(tp) sk[tp--]=0;
for(int j=k-1;~j;j--){
while(tp&&cmb(cl[i][j],cl[i][sk[tp]])) tp--;
if(tp) nx[cl[i][j]]=cl[i][sk[tp]];sk[++tp]=j;
}while(tp) sk[tp--]=0;
}for(int i=1;i<=n;i++){
int nw=dep[a[i]];rt[nw]=rt[dep[a[i-1]]];
add(rt[nw],rt[nw],1,n,dfn[a[i]],1);
if(nx[a[i]]) add(rt[nw],rt[nw],1,n,dfn[lca(a[i],nx[a[i]])],-1);
if(pr[a[i]]) add(rt[nw],rt[nw],1,n,dfn[lca(a[i],pr[a[i]])],-1);
if(nx[a[i]]&&pr[a[i]])
add(rt[nw],rt[nw],1,n,dfn[lca(pr[a[i]],nx[a[i]])],1);
}while(q--){
int x,d;cin>>x>>d,x^=la,d^=la;
la=sum(rt[min(dep[x]+d,m)],rt[dep[x]-1],1,n,dfn[x],low[x]);
cout<<la<<"\n";
}
}int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--) solve();
return 0;
}

[BZOJ4771] 七彩树 题解的更多相关文章

  1. [BZOJ4771]七彩树(主席树)

    https://blog.csdn.net/KsCla/article/details/78249148 用类似经典的链上区间颜色计数问题的做法,这个题可以看成是询问DFS在[L[x],R[x]]中, ...

  2. BZOJ4771 七彩树(dfs序+树上差分+主席树)

    考虑没有深度限制怎么做.显然的做法是直接转成dfs序上主席树,但如果拓展到二维变成矩形数颜色数肯定没法做到一个log. 另一种做法是利用树上差分.对于同种颜色的点,在每个点处+1,dfs序相邻点的lc ...

  3. bzoj4771 七彩树 dfs序+主席树+树链的并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4771 题解 一道不错的树链并的基础练习题. 如果不是树,而是一个数组的话,对于给定区间内的不同 ...

  4. [bzoj4771] 七彩树

    题意 给定一棵n个点,每个点带颜色的有根树.点的编号和颜色编号都在1到n,根的编号为1.m次询问,求x子树中与x距离边数不超过k的点中,颜色的种类数目.每个测试点有多组数据. 分析 不妨设1的父亲为0 ...

  5. BZOJ4771七彩树——可持久化线段树+set+树链的并+LCA

    给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节 点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义dept ...

  6. 【BZOJ4771】七彩树(主席树)

    [BZOJ4771]七彩树(主席树) 题面 BZOJ 题解 如果没有深度限制,每次只询问子树内的颜色个数,除了树套树\(dfs\)序加前驱或者后继强行二维数点之外,还有这样一种做法: 把所有相同颜色的 ...

  7. 【BZOJ4771】七彩树 主席树+树链的并

    [BZOJ4771]七彩树 Description 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j], ...

  8. Vijos1448校门外的树 题解

    Vijos1448校门外的树 题解 描述: 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现 ...

  9. [BZOJ 4771]七彩树(可持久化线段树+树上差分)

    [BZOJ 4771]七彩树(可持久化线段树+树上差分) 题面 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i] ...

  10. 【bzoj4771】七彩树 树链的并+STL-set+DFS序+可持久化线段树

    题目描述 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色,其中第i个节点的颜色为c[i].如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色.定义 ...

随机推荐

  1. CVE-2023-32233 在 Google KCTF 中的漏洞利用方案分析

    这是对前文的补充,增加一种漏洞利用方案的分析,前文地址: https://www.cnblogs.com/hac425/p/17967844/cve202332233-vulnerability-an ...

  2. 【原创】ARM64 实时linux操作系xenomai4(EVL)构建安装简述

    目录 0 环境说明 1 内核构建 2 库编译 方式1 交叉编译 方式2 本地编译 3 测试 单元测试 hectic:EVL 上下文切换 latmus:latency测试 4 RK3588 xenoma ...

  3. 精通 ASP.NET Core MVC (第 7 版) 源码下载

    将使用的 .NET 版本更新到 5.0 版本. GitHub 地址:https://github.com/haoguanjun/pro-asp.net-core-mvc-2

  4. 2024年1月Java项目开发指南8:统一数据返回格式

    有时候返回一个字符串,有时候返回一串数字代码,有时候返回一个对象-- 不过怎么说,我们返回的内容往往具有三个 1.消息代码 code 2.消息内容 msg 3.数据内容 data 接下来,我们要编写一 ...

  5. shell脚本忽略错误继续执行

    在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行.如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set +e 命令来取消该设置. 例如,下面是一个忽略错误并继 ...

  6. Docker Compose - 向远程主机部署服务

    问题描述 通常,我们本地编写 docker-compose.yml 文件,然后运行测试.但是,我们需要在 arm64 环境中进行测试,无法在本地直接运行测试. 我们希望可以在本地编写,然后本地使用 d ...

  7. [转]奇异值分解(SVD)方法求解最小二乘问题的原理

    原文链接:奇异值分解(SVD)方法求解最小二乘问题的原理 翻译 搜索 复制

  8. Hugo 静态博客部署

    I. 前提条件 1.1 安装 Hugo 1.1.1 Windows 1.下载 Hugo(建议下载扩展版):Hugo(github.com) 2.解压 Hugo 压缩包到指定目录. 3.[Win + R ...

  9. macos(m1)编译测试深度学习推理框架

    mnn build tnn

  10. WxPython跨平台开发框架之动态菜单的管理和功能权限的控制

    在一个业务管理系统中,如果我们需要实现权限控制功能,我们需要定义好对应的权限功能点,然后在前端界面中对界面元素的可用性和功能点进行绑定,这样就可以在后台动态分配权限进行动态控制了,一般来说,权限功能点 ...