BZOJ3998: [TJOI2015]弦论

一开始想构造后缀树来着后来发现就是SAM上面跑一下就好了
时间感人QAQ

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

char c;
inline void read(int &a)
{
    a=0;do c=getchar();while(c<'0'||c>'9');
    while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}


struct Node
{
    Node *last,*ch[30];
    bool end;
    int len,time,cur;
    int ans0,ans2;
    Node(){last=NULL;for(len=0;len<=29;len++)ch[len]=NULL;len=0;time=1;ans2=0;}
}*root,*last;
Node *Stack[1000001];
int tot;
inline void add(int data,int place)
{
    Node *tp,*ne=new Node;
    Stack[++tot]=ne;
    ne->time=1;
    ne->end=true;
    ne->len=last->len+1;
    ne->cur=place;
    for(tp=last;tp&&!tp->ch[data];tp=tp->last)tp->ch[data]=ne;
    if(!tp)
     {ne->last=root,last=ne;return;}
     else
       if(tp->len==tp->ch[data]->len-1)
         {ne->last=tp->ch[data];last=ne;return;}   
     else
      {
           Node *a=new Node,*b=tp->ch[data];
           *a=*b;
           a->len=tp->len+1;
           a->cur=-1;
           Stack[++tot]=a;
           a->end=true;
           a->time=0;
           b->last=ne->last=a;
           for(tp;tp&&tp->ch[data]==b;tp=tp->last)
               tp->ch[data]=a;
            last=ne;
      }
}

int h[600001];
int maxn=600000;
Node *S[1000001];
inline void Begin()
{
    for(int i=1;i<=tot;i++)
       S[i]=Stack[i],h[Stack[i]->len]++;
   for(int i=1;i<=maxn;i++) h[i]+=h[i-1];
   for(int i=1;i<=tot;i++) Stack[h[S[i]->len]--]=S[i];
   while(tot)
  {
    if(Stack[tot]->last)
     Stack[tot]->last->time+=Stack[tot]->time;
     Stack[tot]->ans0=Stack[tot]->end?1:0;
     Stack[tot]->ans2=Stack[tot]==root?0:Stack[tot]->time;
    for(int i=0;i<=29;i++)
       if(Stack[tot]->ch[i])
          Stack[tot]->ans0+=Stack[tot]->ch[i]->ans0,
          Stack[tot]->ans2+=Stack[tot]->ch[i]->ans2;
    tot--;
  }
}


inline void Ans0(Node *Cur,int k)
{
    if(Cur!=root&&k<=1)return;
    else if(k>Cur->ans0)
        {puts("-1");return ;}
    else
      {
        if(Cur!=root)k--;
        for(int i=0;i<=29;i++)
          if(Cur->ch[i])
              if(k>Cur->ch[i]->ans0)
                  k-=Cur->ch[i]->ans0;
            else
               {printf("%c",'a'+i),Ans0(Cur->ch[i],k);return;}
      }
}

inline void Ans1(Node *Cur,int k)
{
    if(Cur!=root&&k<=Cur->time)return;
    else if(k>Cur->ans2)
        {puts("-1");return ;}

    else
      {
        if(Cur!=root)k-=Cur->time;
        for(int i=0;i<=29;i++)
          if(Cur->ch[i])
              if(k>Cur->ch[i]->ans2)
                  k-=Cur->ch[i]->ans2;
            else
               {printf("%c",'a'+i),Ans1(Cur->ch[i],k);return;}
      }     
}
char ch[600001];
int main()
{
    scanf("%s",ch);
    int n=strlen(ch); 
    int T,K;
    root=last=new Node;
    Stack[++tot]=root;
    root->end=false;
    for(int i=1;i<=n;i++)
      add(ch[i-1]-'a',i);
    Begin(); 
    scanf("%d%d",&T,&K);
    T?Ans1(root,K):Ans0(root,K);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值