CC TSUBSTR:Substrings on a Tree——题解

https://www.codechef.com/problems/TSUBSTR

https://vjudge.net/problem/CodeChef-TSUBSTR

给一棵点权为字母的树,你只能从任意节点往下走得到一个字符串,求出可得到的不重复字符串数量和其中字典序第k小的字符串(在重新定义字母的字典序前提下)?

垃圾谷歌翻译坑我不浅。

广义后缀自动机处理之后就是BZOJ3998:[TJOI2015]弦论t=0的解法了。

注意空字符串也算。

 

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
const int N=2e6+5;
struct tree{
    int a[26],fa,l;
}tr[N];
struct node{
    int to,nxt;
}e[N];
char s[N];
int tot,cnt,head[N],pos[N];
ll a[N],w[N],size[N],sum[N];
bool vis[N];
queue<int>q;
inline void add(int u,int v){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
inline int insert(int p,int c){
    int np=tr[p].a[c];
    if(np&&tr[np].l==tr[p].l+1)return np;
    np=++tot;tr[np].l=tr[p].l+1;
    for(;p&&!tr[p].a[c];p=tr[p].fa)tr[p].a[c]=np;
    if(!p)tr[np].fa=1;
    else{
    int q=tr[p].a[c];
    if(tr[p].l+1==tr[q].l)tr[np].fa=q;
    else{
        int nq=++tot;tr[nq].l=tr[p].l+1;
        memcpy(tr[nq].a,tr[q].a,sizeof(tr[q].a));
        tr[nq].fa=tr[q].fa;tr[q].fa=tr[np].fa=nq;
        for(;p&&tr[p].a[c]==q;p=tr[p].fa)tr[p].a[c]=nq;
    }
    }
    return np;
}
void bfs(int st){
    tot=1;
    q.push(st);vis[st]=1;
    pos[st]=insert(1,s[st]-'a');
    while(!q.empty()){
    int u=q.front();q.pop();
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])continue;
        q.push(v);vis[v]=1;
        pos[v]=insert(pos[u],s[v]-'a');
    }
    }
}
int main(){
    int len,q;
    scanf("%d%d",&len,&q);
    scanf("%s",s+1);
    for(int i=1;i<len;i++){
    int u,v;
    scanf("%d%d",&u,&v);
    add(u,v);add(v,u);
    }
    bfs(1);
    for(int i=1;i<=tot;i++)w[tr[i].l]++;
    for(int i=1;i<=len;i++)w[i]+=w[i-1];
    for(int i=1;i<=tot;i++)a[w[tr[i].l]--]=i;
    for(int i=tot;i>=1;i--){
    size[a[i]]=1;
    }
    for(int i=tot;i>=1;i--){
    sum[a[i]]=size[a[i]];
    for(int j=0;j<26;j++)
        if(tr[a[i]].a[j])sum[a[i]]+=sum[tr[a[i]].a[j]];
    }
    printf("%lld\n",sum[1]);
    for(int i=1;i<=q;i++){
    ll k;
    scanf("%s%lld",s,&k);
    if(k>sum[1]){puts("-1");continue;}
    int now=1;
    while(k>size[now]){
        k-=size[now];
        for(int j=0;j<26;j++){
        if(k>sum[tr[now].a[s[j]-'a']]){
            k-=sum[tr[now].a[s[j]-'a']];
        }else{
            now=tr[now].a[s[j]-'a'];
            putchar(s[j]);
            break;
        }
        }
    }
    puts("");
    }
    return 0;
}

 

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-04-11 11:47  luyouqi233  阅读(306)  评论(0编辑  收藏  举报