SGU 505 Prefixes and suffixes

题解   现将字符串排序; 那么某前缀在字符串中出现肯定是连续的;写几个案例就知道了;这是记录每个字符在以前缀排名的rank ; 然后将字符串反序; 再排序;依照前缀,可以知道相同名字的后缀也会出现在一段排序好的连续的字符串里面;这样得到前缀的区间为 [a,b],  [c,d]; 只要统计每个字符是否在 a 到 b 之间; 同时满足在 c 到 d 之间;            获取某个前缀的第一个匹配段字符串 和 最后一个字符串也就是 [a,b] 使用了字典树搞; 然后 再用线段树保留最大值和最小值;竟然没有超时, 啊,,哈哈;

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>
using namespace std;

struct date{
    int sta,end;
    date *next[27];
}*root,*rot,tree[412345]; int total;
date *creat_node(){
    for( int i = 0; i < 27; i++ )
    tree[total].next[i] = NULL;
    tree[total].sta = -1;
    tree[total].end = -1;
    return &tree[total++];
}
void inint( ){
    total = 0;
    root = creat_node();
    rot  = creat_node();
}
void insert( string &word,int i,int tab )
{
    date *p; int len = word.length();
    if( tab )p = root;
    else     p = rot;
    for( int j = 0; j < len; j++ )
    {
        int num = word[j] - 'a';
        if( p->next[num] == NULL )
        {
            p->next[num] = creat_node();
            p->next[num]->sta = i;
        }
        p->next[num]->end = i;
        p = p->next[num];
    }
}
int sta,en;
void work( string &word,int tab )
{
    date *p; int len = word.length();
    if( tab ) p = root;
    else p = rot;
    for( int j = 0; j < len; j++ )
    {
        int num = word[j] - 'a';
        if( p->next[num] == NULL ){
            sta = -1; en = -1; return;
        }
        p = p->next[num]; sta = p->sta; en = p->end;
    }
}
struct DAte{
   string sss; int pos;
   bool operator <(const DAte &a )const{
       return sss < a.sss;
   }
}arr[1123456];
struct Date{
   int lt,rt,Max,Min,num;
}node[1123456];
void build( int lt,int rt,int t ){
    node[t].lt = lt; node[t].rt = rt;
    if( lt == rt ){ node[t].num = 1; node[t].Max = node[t].Min = arr[lt].pos; return; }
    int mid = ( lt+rt )>>1;
    build( lt,mid,t<<1 ); build( mid+1,rt,t<<1|1 );
    node[t].Max = max( node[t<<1].Max,node[t<<1|1].Max );
    node[t].Min = min( node[t<<1].Min,node[t<<1|1].Min );
    node[t].num = node[t<<1].num+node[t<<1|1].num;
}
int query( int lt,int rt,int a,int b,int t )
{
    if( node[t].Min > b || node[t].Max < a  )return 0;
    int mid = ( node[t].lt+node[t].rt )>>1;
    if( node[t].lt == lt && node[t].rt == rt )
    {
        if( node[t].Max <= b && node[t].Min >= a )return node[t].num;
        return query( lt,mid,a,b,t<<1 ) + query( mid+1,rt,a,b,t<<1|1 );
    }
    if( node[t<<1].rt >= rt )return query( lt,rt,a,b,t<<1 );
    else if( node[t<<1|1].lt <= lt )return query( lt,rt,a,b,t<<1|1 );
    else return query(lt,mid,a,b,t<<1)+query(mid+1,rt,a,b,t<<1|1);
}
int main( )
{
    int N,M; string str;
    while( scanf("%d",&N) != EOF )
    { 
        for( int i = 0; i < N; i++ )cin>>arr[i].sss;
           sort(arr,arr+N); inint();
        for( int i = 0; i < N; i++ ) arr[i].pos = i;
        for( int i = 0; i < N; i++ ) insert(arr[i].sss,i,1 );
        for( int i = 0; i < N; i++ ) reverse(arr[i].sss.begin(),arr[i].sss.end());
           sort(arr,arr+N);  build(0,N-1,1);
        for( int i = 0; i < N; i++ ) insert(arr[i].sss,i,0);
        scanf("%d",&M);
        for( int i = 1; i <= M; i++ ){
            cin>>str; work(str,1); int a = sta,c = en;
            cin>>str; reverse(str.begin(),str.end());work(str,0); int b = sta,d = en;
            if( a == -1 || b == -1 )cout<<0<<endl;
            else cout<<query( b,d,a,c,1 )<<endl;
        }
    }
    return 0;
}
/*
14
abasbssbs
sfasffsd
adfsas
fdsssf
safas
fsadf
fases
sdesas
aesdf
sefss
aseesaes
fdsasesa
seasea
sedfsas
11
a a
ab ac
fa a
fa s
ac ca
fd sa
fd as
se sa
fs fd
fd fs
ab sb
*/

 

转载于:https://www.cnblogs.com/wulangzhou/p/3438886.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值