好题,又学两个思路。


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

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

  • 颜色相同的点按 \(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. vue 的provide 和 inject

    1.功能说明 在开发过程中,在子组件中如何获取父组件或者祖父级的数据.这个我们之前的做法是在子组件中找到父组件实例,然后使用父组件的数据.这样其实不是很自然. 在vue 中提供了 provide 和 ...

  2. HTML5 新的语义标签

    1.常用的语义标签 意义:语义标签便于阅读代码,也便于搜索引擎解析文档结构与内容 标签 含义 article 定义页面独立的内容区域 aside 定义侧边栏内容 header 定义了文档的头部区域 s ...

  3. Python 潮流周刊#81:在个人电脑上运行 GPT-4 级别的大模型(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  4. idea中yaml文件中文乱码问题解决

    idea打开yaml,或是properties文件,出现中文乱码. 解决步骤: 打开notepad++ ,新建iso-8859-1编码的空文件 将乱码文件通过notepad++直接打开,把正常显示的代 ...

  5. [转]E1接口介绍

    E1 通道本来设计用来传输电话的,每个 E1(带宽 2.048M)可以传 30 路电话,后来扩大的应用范围,可以用作传网络,串口等不同的业务:E1 是一个基本的传输单元,其最终还是通过光纤来传输的,如 ...

  6. 在VS Code中vue引入新版vue-awesome-swiper编译时提示swiper/dist/css/swiper.css无法导入的问题

    在安装vue-awesome-swiper时报错swiper/dist/css/swiper.min.css找不到,如下如: 有的回答安装6.0版本的话需要引入另外一个css import 'swip ...

  7. MySQL使用触发器禁止某行数据某些列的修改

    起因是有来线上演示环境的系统管理员账号经常被禁用导致登录不了,然后需要手动恢复数据状态才行. 原理是利用触发器的旧数据覆盖新数据 delimiter $ CREATE TRIGGER`sys_user ...

  8. 用领域驱动DDD的方式实现购物车-基于abp一代6.2

    废话 之前七七八八看了些DDD相关概念,充血模型.领域事件.领域服务.应用服务等,大致能理解但从未实践.最近在用ABP做个电商模块,尝试用DDD方式来实现购物车功能,感觉还行,下面做个记录. 业务分析 ...

  9. ABC 386 (A~F)

    赛时做的,结果一直在卡D题.打得很失败的一场. ABC 略. D 题意可以转化为:给定\(m\)个黑色或白色的格子,其中: 每个黑色格子和\((1,1)\)作为对角线顶点,构成一个黑色矩形 每个白色格 ...

  10. NoSQL和SQL的区别、使用场景与选型比较

    什么是NoSQL NoSQL,指的是非关系型的数据库.NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称,它具有非关系型.分布式.不提供ACID的数 ...