七彩树 HYSBZ - 4771线段树合并
时间:2019-01-18
本文章向大家介绍七彩树 HYSBZ - 4771线段树合并,主要包括七彩树 HYSBZ - 4771线段树合并使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Part1
本题是查找一个节点x的字树内深度与其相差不超过d的节点有多少种颜色。如果单纯考虑有多少个点,应该如何求,如何维护深度在一个区间内且是x的后代的信息呢?我们可以每个节点用一颗以下标为权值的线段树来维护(后面记为线段树X)。用线段树合并来完成所有信息的处理。但如何查找深度在一个区间里的信息呢?我们可以将每个节点重新以深度编号,编号与深度正相关(也就是编号越大的点深度越大),在预处理处每个深度最大的编号。这样就可以区间求和来解决这一简化后的问题。
Part2
对于“出现了多少种本质不同的颜色”这一句话,不难联想到Turing Tree这道题。只不过变为了在子树内查询而不是在序列上,但大体还是类似的。
相同颜色的节点,我们只用深度最浅(也就是离根最近)的节点。故我们可以对每个节点再开一个线段树维护这个节点的子树内每种颜色的节点的最浅位置(后面记为线段树Y),每次线段树合并时去掉深度大的颜色相同的点在当前节点的线段树X里的贡献。每个节点的线段树X只存每种颜色所在深度最浅的位置(重新编号后的)。
Part3
题目里的小细节注意一下。(1<=T<=500),如果对每一组测试数据都清空数组会TLE,由于n和m的总和不超过500000,故每次只用清空上次使用过的数组即可。
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define M 100005
#define INF 1061109567
using namespace std;
bool cur1;
void check_max(int &x,int y){if(x<y)x=y;}
void check_min(int &x,int y){if(x>y)x=y;}
struct E{
int to,nx;
}edge[M<<1];
int tot,head[M];
void Addedge(int a,int b){
edge[++tot].to=b;
edge[tot].nx=head[a];
head[a]=tot;
}
int C[M],fa[M],dep[M],n,id;
int ID[M];//按照深度排序
int ID_dep[M];//每个排序后的节点的深度
struct SegT2{
int tot;
int Root[M],Lson[M*50],Rson[M*50];
int sum[M*50];//每个子树内的信息 和Turing Tree没什么区别
void Create(int &p){
int tid=++tot;
Lson[tid]=Lson[p];
Rson[tid]=Rson[p];
sum[tid]=sum[p];
p=tid;
}
SegT2(){tot=0;}
void clear(){
for(int i=1;i<=n;i++)Root[i]=0;
for(int i=0;i<=tot;i++)Lson[i]=Rson[i]=sum[i]=0;
tot=0;
}
void Updata(int L,int R,int x,int op,int &tid){
Create(tid);
sum[tid]+=op;
if(L==R)return;
int mid=(L+R)>>1;
if(x<=mid)Updata(L,mid,x,op,Lson[tid]);
else Updata(mid+1,R,x,op,Rson[tid]);
}
int Query(int L,int R,int Lx,int Rx,int tid){
if(Lx<=L&&R<=Rx)return sum[tid];
int mid=(L+R)>>1;
if(Rx<=mid)return Query(L,mid,Lx,Rx,Lson[tid]);
else if(Lx>mid)return Query(mid+1,R,Lx,Rx,Rson[tid]);
else return Query(L,mid,Lx,mid,Lson[tid])+Query(mid+1,R,mid+1,Rx,Rson[tid]);
}
int Merge(int x,int y,int L,int R){
if(!x||!y)return x+y;
int tid=++tot;
int mid=(L+R)>>1;
sum[tid]=sum[x]+sum[y];
Lson[tid]=Merge(Lson[x],Lson[y],L,mid);
Rson[tid]=Merge(Rson[x],Rson[y],mid+1,R);
return tid;
}
void Text(int tid,int L,int R){
int mid=(L+R)>>1;
if(L==R)return;
Text(Lson[tid],L,mid);
Text(Rson[tid],mid+1,R);
}
}ST2;
struct SegT1{//颜色COLOR
int tot;
int Root[M],Lson[M*50],Rson[M*50];
int num[M*50];//每个颜色所对应的最浅位置
int Pc;
void Create(int &p){
int tid=++tot;
Lson[tid]=Lson[p];
Rson[tid]=Rson[p];
num[tid]=num[p];
p=tid;
}
SegT1(){tot=0;}
void clear(){
for(int i=0;i<=n;i++)Root[i]=0;
for(int i=0;i<=tot;i++)Rson[i]=0,Lson[i]=0,num[i]=INF;//memset会T,手动清空
tot=0;
}
void Updata(int L,int R,int x,int d,int &tid){
Create(tid);
if(L==R){
if(num[tid]>n||ID_dep[num[tid]]>ID_dep[d]){
if(num[tid]<=n)ST2.Updata(1,n,num[tid],-1,ST2.Root[Pc]);//更新操作
ST2.Updata(1,n,d,1,ST2.Root[Pc]);
num[tid]=d;
}
return;
}
int mid=(L+R)>>1;
if(x<=mid)Updata(L,mid,x,d,Lson[tid]);
else Updata(mid+1,R,x,d,Rson[tid]);
}
int Query(int L,int R,int x,int &tid){
if(L==R)return num[tid];
int mid=(L+R)>>1;
if(x<=mid)return Query(L,mid,x,Lson[tid]);
else return Query(mid+1,R,x,Rson[tid]);
}
int Merge(int x,int y,int L,int R){
if(!x||!y)return (x+y);
int tid=++tot;
if(L==R){
if(num[x]>n&&num[y]>n){
num[tid]=num[x];
return tid;
}
int res=max(num[x],num[y]);
if(res<=n)ST2.Updata(1,n,res,-1,ST2.Root[Pc]);//删去深度较大的
num[tid]=min(num[x],num[y]);
return tid;
}
int mid=(L+R)>>1;
Lson[tid]=Merge(Lson[x],Lson[y],L,mid);
Rson[tid]=Merge(Rson[x],Rson[y],mid+1,R);
return tid;
}
}ST1;
int dep_mx[M];
void dfs(int now){
for(int i=head[now];i;i=edge[i].nx){//把深度求出来
int nxt=edge[i].to;
if(nxt==fa[now])continue;
dep[nxt]=dep[now]+1;
dfs(nxt);
}
}
void redfs(int now){
ST1.Root[now]=ST2.Root[now]=0;
for(int i=head[now];i;i=edge[i].nx){
int nxt=edge[i].to;
redfs(nxt);
ST1.Pc=now;
ST1.Root[now]=ST1.Merge(ST1.Root[nxt],ST1.Root[now],1,id);
ST2.Root[now]=ST2.Merge(ST2.Root[nxt],ST2.Root[now],1,n);
}
ST1.Pc=now;
ST1.Updata(1,id,C[now],ID[now],ST1.Root[now]);
}
bool cmp(int x,int y){return dep[x]<dep[y];}
void Init(){
dep[1]=1;
ST1.clear();
ST2.clear();
tot=0;
for(int i=1;i<=n;i++)head[i]=0,dep_mx[i]=0;
}
int B[M],P[M];
bool cur2;
int main(){
int T;
scanf("%d",&T);
while(T--){
int m;
scanf("%d%d",&n,&m);
Init();
for(int i=1;i<=n;i++)scanf("%d",&C[i]),B[i]=C[i];
sort(B+1,B+n+1);
id=unique(B+1,B+n+1)-B-1;
for(int i=1;i<=n;i++)C[i]=lower_bound(B+1,B+id+1,C[i])-B;//离散化
for(int i=2;i<=n;i++){
scanf("%d",&fa[i]);
Addedge(fa[i],i);
}
for(int i=1;i<=n;i++)P[i]=i;
dfs(1);
sort(P+1,P+n+1,cmp);
for(int i=1;i<=n;i++)ID[P[i]]=i;//重新标号
for(int i=1;i<=n;i++)ID_dep[ID[i]]=dep[i];//存每一个编号对应的深度
for(int i=1;i<=n;i++)check_max(dep_mx[dep[i]],ID[i]);//预处理每个深度最大的编号
redfs(1);
int ans=0;
while(m--){
int x,d;
scanf("%d%d",&x,&d);
x^=ans,d^=ans;
printf("%d\n",ans=ST2.Query(1,n,dep_mx[dep[x]-1]+1,dep_mx[dep[x]+d]==0?n:dep_mx[dep[x]+d],ST2.Root[x]));//由于怕深度会超过子树最深深度
- 如何与深度学习服务器优雅的交互?
- 比特币大跌又反弹30%,区块链技术与企业级有着怎样的关系?
- 十个实用MySQL函数
- 使用Apprenda和R分析应用程序工作负载数据
- 实现微信朋友圈所有动态点赞的自动化用例
- 后台设计的一些总结
- 2017年区块链当中的黑客大事件
- 5个云安全解决方案的注意事项
- 深入剖析ASP.NET的编译原理之二:预编译(Precompilation)
- 深入剖析ASP.NET的编译原理之二:预编译(Precompilation)
- Nodejs学习笔记(十六)--- Pomelo介绍&入门
- 美团再出幺蛾子,启动美团打车项目,滴滴感到威胁了吗?
- 深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)
- 深入剖析ASP.NET的编译原理之一:动态编译(Dynamical Compilation)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法