题意:
一开始有一个空串t,你每次有两种操作:
1.在t的末尾加上一个字符,花费时间为1
2.在集合S中,取出所有前缀为t的字符串,进行字典序排序之后,得到s1…s2…sk。你可以将t变为第i个字符串,花费时间为i。
现在有n个字符串,字符串的构造方法为
si = x c
表示字符串i是通过在串x的末尾添加字符c得到。
接下来告诉你一个k和a[1],a[2],a[3]…a[k]
表示构造出来的s[a[i]](1<=i<=k)是集合S中的字符串。
并且问你构造a[i]需要至少多少时间
题解:
很明显是个树形DP,按照给你的构造方法去建树
那么转移有两种情况:
1.dp[i]=dp[fa]+1 首先是第一种操作
2.dp[i]=query(1,fa) 表示从父亲到根节点这条链上进行第二种操作转移
对于第二种使用树链剖分,首先按照字典序每层进行排序,然后先做字典序小的部分,对于当前如果是在S集合中的话,我们将1~x这条链上的值+1,表示如果要从这条链上进行跳转,就需要加入这个点的影响。并且跳转只能在S集合中的点上进行跳转,非S集合中的点只能一步一步走过来,否则可能会出问题。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
struct node
{
int to,next,v;
}e[N*2];
int head[N],cnt,tim,fa[N],son[N],dep[N],top[N],en[N],siz[N],pos[N];
ll flag[N*4],sum[N*4],a[N];
int n,m,rt,mod;
void add(int x,int y,int v)
{
e[cnt].to=y;
e[cnt].next=head[x];
e[cnt].v=v;
head[x]=cnt++;
}
void dfs1(int u)
{
siz[u]=1;
for (int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if (v!=fa[u])
{
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if (son[u]==0||siz[v]>siz[son[u]])
son[u]=v;
}
}
}
void dfs2(int u,int f)
{
tim++;
top[u]=f;
pos[u]=tim;
if (son[u]) dfs2(son[u],f);
for (int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if (v!=fa[u]&&v!=son[u])
{
dfs2(v,v);
}
}
en[u]=tim;
}
void pushdown(int root)
{
if(!flag[root])
return ;
sum[root<<1]+=flag[root];
sum[root<<1|1]+=flag[root];
flag[root<<1]+=flag[root];
flag[root<<1|1]+=flag[root];
flag[root]=0;
}
void add(int l,int r,int root,int ql,int qr,int val)
{
if(l>=ql&&r<=qr)
{
sum[root]+=val;
flag[root]+=val;
return ;
}
pushdown(root);
int mid=l+r>>1;
if(mid>=ql)
add(l,mid,root<<1,ql,qr,val);
if(mid<qr)
add(mid+1,r,root<<1|1,ql,qr,val);
sum[root]=min(sum[root<<1],sum[root<<1|1]);
}
int ask(int l,int r,int root,int ql,int qr)
{
if(l>=ql&&r<=qr)
return sum[root];
int mid=l+r>>1;
pushdown(root);
int ans=1e9;
if(mid>=ql)
ans=ask(l,mid,root<<1,ql,qr);
if(mid<qr)
ans=min(ans,ask(mid+1,r,root<<1|1,ql,qr));
return ans;
}
void update(int x,int y,int val)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
add(1,n,1,pos[top[x]],pos[x],val);
x=fa[top[x]];
}
if (pos[x]>pos[y]) swap(x,y);
add(1,n,1,pos[x],pos[y],val);
}
int query(int x,int y)
{
int ans=1e9;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans=min(ans,ask(1,n,1,pos[top[x]],pos[x]));
x=fa[top[x]];
}
if (pos[x]>pos[y]) swap(x,y);
ans=min(ans,ask(1,n,1,pos[x],pos[y]));
return ans;
}
int dp[N],in[N];
struct edge{
int p,v;
bool operator< (const edge& aa)const {
return v<aa.v;
}
};
vector<edge>vec[N];
void dfs(int x,int fa){
for(int i=head[x];~i;i=e[i].next)
vec[x].push_back({e[i].to,e[i].v});
sort(vec[x].begin(),vec[x].end());
if(x!=1){
if(in[x])
update(1,x,1);
dp[x]=dp[fa]+1;
if(in[x])
dp[x]=min(dp[x],query(1,fa));
update(x,x,dp[x]);
}
for(edge ne:vec[x])
dfs(ne.p,x);
}
int que[N];
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n),n++;
int x;
char s[2];
for(int i=2;i<=n;i++){
scanf("%d%s",&x,s);
add(x+1,i,s[0]-'a');
}
dfs1(1),dfs2(1,1);
//update(1,1,1e9);
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)scanf("%d",&que[i]),in[que[i]+1]=1;
dfs(1,0);
for(int i=1;i<=q;i++)
printf("%d\n",dp[que[i]+1]);
return 0;
}