一直TLE的原因竟然是数组开太大了导致\(memset\)清空耗时超限,亏我还调了1天啊(T^T)


题目大意

给定一颗树,每个节点都有一个颜色,要求多次询问某个节点\(x\)的子树中深度不超过\(d\)的节点中,有多少种不同的颜色,强制在线。

概述

首先,我们可以考虑两个相同颜色的节点对答案的贡献。

很显然,他对他们自己所有的祖先的答案贡献都为\(1\),在他们\(lca\)及以上的地方被重复计算了一次,所以说都需要减去\(1\);

然后考虑对于相同颜色的节点,对相同颜色节点的\(dfs\)序维护一个set,每一次去寻找他的前趋与后继,进行我们刚刚抽离出来讨论的操作,这样的话就可以很好的解决这个问题。

那应该怎么维护呢?很显然,如果没有距离限制,在每个结点处维护一颗线段树足矣。如果有距离限制,受『谈笑风生』一题的启发,我们可以以深度来维护一颗主席树,这只需要我们在进行上一段讨论的操作时按照深度顺序进行操作,对原操作是毫无影响的。

具体见代码,常数略大:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct cc{
int to,nex;
}e[maxn*2];
int head[maxn],tot;
int a[maxn],b[maxn];
int ls[maxn*50],rs[maxn*50],sum[maxn*50],cnt,rt[maxn];
inline int read()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void update(int &u,int pos,int l,int r,int t,int num)
{
u=++tot;
sum[u]=sum[pos]+num,rs[u]=rs[pos],ls[u]=ls[pos];
if(l==r) return ;
int mid=(l+r)>>1;
if(t<=mid) update(ls[u],ls[pos],l,mid,t,num);
else update(rs[u],rs[pos],mid+1,r,t,num);
}
int query(int ll,int rr,int l,int r,int u)
{
if((ll<=l&&r<=rr)||(!u)) return sum[u];
int mid=(l+r)>>1;
if (rr<=mid) return query(ll,rr,l,mid,ls[u]);
if(ll>mid)return query(ll,rr,mid+1,r,rs[u]);
return query(ll,rr,l,mid,ls[u])+query(ll,rr,mid+1,r,rs[u]);
}
void add(int u,int v)
{
++cnt;
e[cnt].to=v;
e[cnt].nex=head[u];
head[u]=cnt;
}
int fa[maxn][19],col[maxn],dep[maxn],low[maxn],dfn[maxn],tim,id[maxn],p[maxn],lg[maxn];
int n,m;
bool cmp(int x,int y)
{
return dep[x]<dep[y];
}//原来可以不用打包啊,震惊
void dfs(int u)
{
++tim,dfn[u]=tim,p[tim]=u;
for(int i=head[u];i!=-1;i=e[i].nex)
dep[e[i].to]=dep[u]+1,dfs(e[i].to);
low[u]=tim;
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=lg[dep[x]-dep[y]];i>=0;--i)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y) return x;
for(int i=lg[dep[x]];i>=0;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
set<int> g[maxn];
void init()
{
memset(fa,0,sizeof fa);
tim=cnt=tot=0;
memset(head,-1,sizeof head);
memset(rt,0,sizeof rt);
}
set<int>::iterator it;
int main()
{
int T;
T=read();
for(int _=1;_<=T;++_)
{
int aa,bb;
init();
n=read(),m=read();
for(int i=1;i<=n;++i) col[i]=read(),id[i]=i,g[i].clear(),lg[i]=lg[i>>1]+1;
for(int i=2;i<=n;++i) fa[i][0]=read(),add(fa[i][0],i);
dep[1]=1,dfs(1);
for(int j=1;j<=18;++j)
for(int i=1;i<=n;++i)
fa[i][j]=fa[fa[i][j-1]][j-1];
sort(id+1,id+n+1,cmp);
for(int i=1;i<=n;++i)
{
int now=id[i];aa=bb=0;
it=g[col[now]].lower_bound(dfn[now]);
update(rt[dep[now]],rt[dep[id[i-1]]],1,n,dfn[now],1);
if(it!=g[col[now]].end())
bb=p[(*it)],update(rt[dep[now]],rt[dep[now]],1,n,dfn[lca(now,bb)],-1);
if(it!=g[col[now]].begin())
--it,aa=p[(*it)],update(rt[dep[now]],rt[dep[now]],1,n,dfn[lca(now,aa)],-1);
if(aa&&bb) update(rt[dep[now]],rt[dep[now]],1,n,dfn[lca(aa,bb)],1);
g[col[now]].insert(dfn[now]);
}
int lst=0;
for(int i=1;i<=m;++i)
{
aa=read(),bb=read();
aa^=lst,bb^=lst;
lst=query(dfn[aa],low[aa],1,n,rt[min(dep[aa]+bb,dep[id[n]])]);
printf("%d\n",lst);
}
}
return 0;
}

【BZOJ 4771】七彩树的更多相关文章

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

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

  2. BZOJ.4771.七彩树(可持久化线段树)

    BZOJ 考虑没有深度限制,对整棵子树询问怎么做. 对于同种颜色中DFS序相邻的两个点\(u,v\),在\(dfn[u],dfn[v]\)处分别\(+1\),\(dfn[LCA(u,v)]\)处\(- ...

  3. BZOJ 4771 七彩树(可持久化线段树合并)

    题意 https://www.lydsy.com/JudgeOnline/problem.php?id=4771 思路 和 HDU 3333 其实有点像,不过是把序列的问题放在了树上,多维护一个深度即 ...

  4. BZOJ - 4771 七彩树 (可持久化线段树合并)

    题目链接 对每个结点建立两棵线段树,一棵记录该结点的子树下每种颜色对应的最小深度,另一棵记录子树下的每个深度有多少结点(每种颜色的结点只保留最浅的深度即可),自底而上令父节点继承子结点的线段树,如果合 ...

  5. bzoj 4771: 七彩树

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

  6. bzoj 4771: 七彩树 树链的并+可持久化线段树

    题目大意: 给定一颗树,询问树中某个点x的子树中与其距离不超过d的所有点中本质不同的颜色数 强制在线 题解: 一下午终于把这道题叉掉了. 写了三个算法,前两个都是错的,后一个是%的网上大爷们的题解. ...

  7. BZOJ 4771: 七彩树 可持久化线段树+树链的并

    这个思路挺有意思的 ~ 利用树链的并来保证每个颜色只贡献一次,然后用可持久化线段树维护 code: #include <set> #include <cstdio> #incl ...

  8. BZOJ 4771 主席树+倍增+set

    思路: 因为有深度的限制,并且我们是在线段树上维护权值,所以我们把点按照dep排序,然后一个一个修改...主席树的下标就是dfs序,子树的查询就是区间查询... 但是发现这样怎么去维护LCA呢...因 ...

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

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

  10. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

随机推荐

  1. docker私有仓库搭建及使用

      1.下载官方镜像 sudo docker pull registry 下载完成后,docker images可以查看到pull下来的镜像registry 2.启动registry容器,用于提供私有 ...

  2. 用golang刷LeetCode

    用golang刷LeetCode 用Go语言刷LeetCode记录,只是为了练习Go语言,能力有限不保证都是最优解,只能在此抛转引玉了. 数据结构和算法 数据结构和算法是程序员的命根子,没了命根子也就 ...

  3. Sqlserver语句获取本周、上一周、本月数据

    sql语句获取本周.上一周.本月数据 获取周数据 1 本周 2 select * from table1 where datediff(week,时间字段,getdate()) = 0 3 上周 4 ...

  4. THINKPHP_(1)_修改TP源码,支持对中文字符串按拼音进行排序。

    问题:TP从服务器数据中取出的collection数据,当进一步在网页中进行分页显示时,需要调用order函数,实现类似如下图的排序. 当点击页面中的相关内容时,实现对服务器数据进行重排,就要调用TP ...

  5. Lidar激光雷达市场

    Lidar激光雷达市场 近年来,激光雷达技术在飞速发展,从一开始的激光测距技术,逐步发展了激光测速.激光扫描成像.激光多普勒成像等技术,如今在无人驾驶.AGV.机器人等领域已相继出现激光雷达的身影. ...

  6. 机器学习PAL产品优势

    机器学习PAL产品优势 PAI支持丰富的机器学习算法.一站式的机器学习体验.主流的机器学习框架及可视化的建模方式.本文介绍PAI的产品优势. 丰富的机器学习算法 PAI的算法都经过阿里巴巴集团大规模业 ...

  7. 图分析Rapids cuGraph

    图分析Rapids cuGraph 英伟达(Nvidia)建立的新的开源库可能是推进分析和使图形数据库更快的秘密要素. 在Nvidia GPU上进行并行处理. Nvidia很久以前就不再只是" ...

  8. 工作流中的流程追溯!详细解析Activiti框架中的历史组件

    Activit中的历史简介 历史: Activiti中的一个组件,可以捕获发生在进程执行中的信息并永久的保存.与运行时数据不同的是,当流程实例运行完成之后它还会存在于数据库中 历史实体对象有5个: H ...

  9. .Net Core with 微服务 - Consul 注册中心

    上一次我们介绍了 Ocelot 网关的基本用法.这次我们开始介绍服务注册发现组件 Consul 的简单使用方法. 服务注册发现 首先先让我们回顾下服务注册发现的概念. 在实施微服务之后,我们的调用都变 ...

  10. 【模拟8.09】轰炸行动(bomb) (tarjan缩点和拓扑排序)

    很显然的tarjan嘛......拓扑也很容易想到 我是不会说我因为懒把拓扑改成DFS结果扔了40分然后就是纯板子了 因为我们一条路径的点如果不是一个一个炸,同时炸两个,他们一定会相互到达.... 找 ...