【JZOJ4061】【JSOI2015】字符串树

11 篇文章 0 订阅
4 篇文章 0 订阅

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

这种题我们考虑什么用打棵字典树和lca来解决。我们对于一个点i,存储从i到根节点路径上的所有字符串,这可以用类似主席树的方法来解决。然后对于一个询问[x,y],我们查出x和y的最近公共祖先t,那么答案显然是ans[x]+ans[y]-2*ans[t],用trie匹配一下就好了。

代码

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=200005,maxn1=1000005;
int first[maxn],last[maxn],next[maxn],f[maxn1][26],g[maxn][20],ans;
int n,m,i,t,j,k,l,x,y,d[maxn],num,v[maxn],len,z,c[maxn1],deep[maxn];
char s[maxn][20],s1[20];
bool bz[maxn];
void lian(int x,int y){
    last[++num]=y;next[num]=first[x];first[x]=num;
}
void insert(int j,int v1,int &v){
    v=++num;c[v]=c[v1];int t,k;
    for (k=0;k<=25;k++)
        f[v][k]=f[v1][k];
    if (j==len+1){
        c[v]++;return;
    }
    insert(j+1,f[v1][s[l][j]-97],f[v][s[l][j]-97]);
    c[v]++;
}
int lca(int x,int y){
    int i,j,t,k,l;
    if (deep[x]<deep[y]) swap(x,y);
    for (i=log(n)/log(2);i>=0;i--)
        if (deep[g[x][i]]>=deep[y]) x=g[x][i];
    if (x==y) return x;
    for (i=log(n)/log(2);i>=0;i--)
        if (g[x][i]!=g[y][i]) x=g[x][i],y=g[y][i];
    return g[x][0];
}
int find(int i,int v){
    if (!v) return 0;
    if (i==l+1) return c[v];
    return find(i+1,f[v][s1[i]-97]);
}
int main(){
    freopen("strings.in","r",stdin);freopen("strings.out","w",stdout);
    scanf("%d",&n);
    for (i=1;i<=n-1;i++)
        scanf("%d%d%s\n",&x,&y,s[i]+1),lian(x,y),lian(y,x);
    v[1]=j=1;i=0;bz[1]=true;deep[1]=1;
    num=0;
    while (i<j){
        x=v[++i];
        for (t=first[x];t;t=next[t]){
            if (bz[last[t]]) continue;
            bz[last[t]]=true;g[last[t]][0]=x;v[++j]=last[t];
            l=t/2;if (t%2)l++;len=strlen(s[l]+1);deep[v[j]]=deep[x]+1;
            insert(1,d[x],d[last[t]]);
        }
    }
    for (j=1;j<=log(n)/log(2);j++)
        for (i=1;i<=n;i++)
            g[i][j]=g[g[i][j-1]][j-1];
    scanf("%d",&m);
    for (i=1;i<=m;i++){
        scanf("%d%d%s",&x,&y,s1+1);
        t=lca(x,y);l=strlen(s1+1);
        ans=find(1,d[x])+find(1,d[y])-find(1,d[t])*2;
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值