【AC自动机 可持久化线段树】魔法串(2022.5.28)
有一些算法,懂了的人明了于心,以一言为多余,不懂的人怎么也不懂...
题目
3 魔法串(magic.c/cpp/pas)
3.1 题目描述
给你一棵 n + 1 个结点的有根树,结点从 0 到 n 标号,其中 0 为根结点。
这是一棵魔法树。这棵树的每条边有一个魔力值,同一个结点连向不同子结点的边的魔
力值不同。一个结点所代表的魔法串是从根一直走到这个结点,经过的魔力值依次排列形成
的有序序列,另外,一个串是魔法串当且仅当它被一个结点所代表。
现在,为了使用强大的魔法,你需要对每个魔法串,找到最长的是它后缀的魔法串。为
了方便输出,你只需要输出代表这个魔法串的结点的标号即可。若没有这个魔法串,请输出 0。
3.2 输入格式
第一行一个整数 n,代表除根以外的结点个数。
第二行 n 个整数,第 i 个整数 Pi 代表标号为 i 的结点的父亲标号。
第三行 n 个整数,第 i 个整数 Ci 代表标号为 i 的结点连向父亲的边的魔力值
3.3 输出格式
输出一行 n 个整数,第 i 个整数表示第 i 个结点代表的魔法串的答案。
3.4 样例输入
7
0 0 1 1 2 4 5
1 2 3 2 1 1 3
3.5 样例输出
0 0 0 2 1 5 3
3 .6 数据范围与约定
对于前30%的数据,n≤2000;
对于100%的数据,1≤n≤200000, 0≤Pi<i, 1≤Ci≤n。
解思
(既然被人说题解太简陋,那我还是写详细一点吧)
前置知识:AC自动机不会的建议先学一下,这个知识非常重要!
会AC自动机的同学,大概一眼就能看出来此题求最长后缀的点明显是求AC自动机中的fail指针。
于是我就自信地写了个AC自动机的板子套了个unordered_map交上去(然后发现空间炸了)
首先这题是肯定需要补全AC自动机的(把fail指针化做边,直接从当前点的fail点继承fail点的子儿子)
重新审视一下数据范围,200000的范围意味着需要一个logn查找当前点连向的点是否有权值为Ci的点,同时又需要继承之前的状态,考虑可持久化线段树维护。转移边最多只有n条,所以最多进行n次转移,一共复杂度O(nlogn)
于是乎就可以过了...
上代码!
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int f=1,j=0;char w=getchar();
while(w>'9'||w<'0'){
if(w=='-')f=-1;
w=getchar();
}
while(w>='0'&&w<='9'){
j=(j<<3)+(j<<1)+w-'0';
w=getchar();
}
return f*j;
}
const int N=200001;
int n,fa[N],sum[N],f[N],depth[N];
int root[N],ls[N*20],rs[N*20],val[N*20],tail_t;
int head[N],to[N],front[N],tail;
bool use[N];
void addline(int x,int y){
to[++tail]=y;
front[tail]=head[x];
head[x]=tail;
return ;
}
int find(int nown,int l,int r,int aim){
if(nown==0)return 0;
if(l==r)return val[nown];
int mid=(l+r)/2;
if(aim<=mid)return find(ls[nown],l,mid,aim);
else return find(rs[nown],mid+1,r,aim);
}
void inherit(int x,int &y,int l,int r,int aim,int w){
y=++tail_t;
if(l==r){
val[y]=w;
return ;
}
int mid=(l+r)/2;
if(aim<=mid)rs[y]=rs[x],inherit(ls[x],ls[y],l,mid,aim,w);
else ls[y]=ls[x],inherit(rs[x],rs[y],mid+1,r,aim,w);
return ;
}
void work(){
deque<int>line,Q;
int now_dep=2;
for(int k=head[0];k;k=front[k]){
int x=to[k];
depth[x]=1;
inherit(root[0],root[0],1,n,sum[x],x);
for(int a=head[x];a;a=front[a]){
int b=to[a];
depth[b]=2;
line.push_back(b);
}
}
for(int k=head[0];k;k=front[k])root[to[k]]=root[0];
while(!line.empty()){
int nown=line.front();line.pop_front();
if(depth[nown]!=now_dep){
now_dep++;
while(!Q.empty())root[Q.front()]=root[f[Q.front()]],Q.pop_front();
}
Q.push_back(nown);
f[nown]=find(root[fa[nown]],1,n,sum[nown]);
inherit(root[fa[nown]],root[fa[nown]],1,n,sum[nown],nown);
for(int k=head[nown];k;k=front[k]){
int x=to[k];
depth[x]=depth[nown]+1;
line.push_back(x);
}
}
return ;
}
signed main(){
//freopen("magic.in","r",stdin);
//freopen("magic.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
fa[i]=read();
addline(fa[i],i);
}
for(int i=1;i<=n;i++)sum[i]=read();
work();
for(int i=1;i<=n;i++)printf("%d ",f[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】