UVA - 12338 Anti-Rhyme Pairs【后缀数组】+【ST】or【线段树】

UVA12338

分析:将n字符串拼接后求出后缀数组,当查询x和y时,即是求height[i]到height[j]之间的最小值,ij为xy对应的排名。

这里height的最小值可以用线段树维护也可以用st表来维护(为啥我用线段树比st表快??)

ST表代码:

#include "cstdio"
#include "cstring"
#include "iostream"
#include "algorithm"
#include "bits/stdc++.h"
using namespace std;
int s[1100010];
char ts[1100010];
int sa[1100010],x[1100010],y[1100010],c[1100010],n,m,height[1100010],rk[1100010];
void Suffix(){
    for(int i=0;i<m;i++) c[i]=0;
    for(int i=0;i<n;i++) c[x[i]=s[i]]++;
    for(int i=0;i<m;i++) c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1) {
        int p=0;
        for(int i=n-k;i<n;i++) y[p++]=i;
        for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[y[i]]]++;
        for(int i=0;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(int i=1;i<n;i++)
            x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
        if(p>=n) break;
        m=p;
    }
}
void getheight(){
    for(int i=0;i<n;i++) rk[sa[i]]=i;
    for(int i=0,k=0;i<n;i++){
        if(rk[i]){
            if(k) --k;
            else k=0;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k]) k++;
            height[rk[i]]=k;
        }
    }
}
//////////////////////////////////////////////////////////////////////////////////////
int dp[2000004][40];
int be[100004];
void init(){
    //memset(dp,0x3f3f3f3f, sizeof(dp));
    for (int i = 0; i < n; ++i) {
        dp[i][0]=height[i];
    }
    for (int j = 1; (1<<j) < n; ++j) {
        for (int i = 0; i + (1<<j) - 1 < n; ++i) {
            dp[i][j]=0x3f3f3f3f;
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
        }
    }
}
int que(int l,int r){
    int k = log2(r-l+1);
    return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int LEN[100004];
int main(){
    int t;
    cin>>t;
    int kase = 1;
    while(t--){
        int N;
        cin>>N;
        m = 30;
        n = 0;
        for (int i = 0; i < N; ++i) {
            scanf("%s",ts);
            int len = strlen(ts);
            LEN[i+1]=len;
            be[i+1]=n;
            for (int j = 0; j < len; ++j) {
                s[n++]=ts[j]-'a'+1;
            }
            s[n++]=m++;
        }
        s[n++]=0;
        Suffix();
        getheight();
        int q;
        cin>>q;
        init();
        printf("Case %d:\n",kase++);
        while(q--){
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==y){
                printf("%d\n",LEN[x]);
                continue;
            }
            x = rk[be[x]];
            y = rk[be[y]];
            if(x>y)swap(x,y);
            printf("%d\n",que(x+1,y));
        }
    }
}

线段树:

#include "cstdio"
#include "cstring"
#include "iostream"
#include "algorithm"
#include "bits/stdc++.h"
using namespace std;
int s[1100010];
char ts[1100010];
int sa[1100010],x[1100010],y[1100010],c[1100010],n,m,height[1100010],rk[1100010];
void Suffix(){
    for(int i=0;i<m;i++) c[i]=0;
    for(int i=0;i<n;i++) c[x[i]=s[i]]++;
    for(int i=0;i<m;i++) c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1) {
        int p=0;
        for(int i=n-k;i<n;i++) y[p++]=i;
        for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[y[i]]]++;
        for(int i=0;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(int i=1;i<n;i++)
            x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
        if(p>=n) break;
        m=p;
    }
}
void getheight(){
    for(int i=0;i<n;i++) rk[sa[i]]=i;
    for(int i=0,k=0;i<n;i++){
        if(rk[i]){
            if(k) --k;
            else k=0;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k]) k++;
            height[rk[i]]=k;
        }
    }
}
//////////////////////////////////////////////////////////////////////////////////////
struct node
{
    int l,r,w;
}t[4100010];
int be[100004];
void b(int rt,int l,int r){
    t[rt].l=l,t[rt].r=r;
    if(l==r){
        t[rt].w=height[l];
    }
    else {
        int mid = (l+r)>>1;
        b(rt<<1,l,mid),b(rt<<1|1,mid+1,r);
        t[rt].w=min(t[rt<<1].w,t[rt<<1|1].w);
    }
}
int que(int rt,int l,int r){
    if(t[rt].l>=l&&t[rt].r<=r)return t[rt].w;
    else {
        int res = 2e9;
        int mid = (t[rt].l+t[rt].r)>>1;
        if(l<=mid)res=min(res,que(rt<<1,l,r));
        if(r>mid)res=min(res,que(rt<<1|1,l,r));
        return res;
    }
}
int LEN[100004];
int main(){
    int t;
    cin>>t;
    int kase = 1;
    while(t--){
        int N;
        cin>>N;
        m = 30;
        n = 0;
        for (int i = 0; i < N; ++i) {
            scanf("%s",ts);
            int len = strlen(ts);
            LEN[i+1]=len;
            be[i+1]=n;
            for (int j = 0; j < len; ++j) {
                s[n++]=ts[j]-'a'+1;
            }
            s[n++]=m++;
        }
        s[n++]=0;
        Suffix();
        getheight();
        int q;
        cin>>q;
        b(1,0,n-1);
        printf("Case %d:\n",kase++);
        while(q--){
            int x,y;
            scanf("%d%d",&x,&y);
            if(x==y){
                printf("%d\n",LEN[x]);
                continue;
            }
            x = rk[be[x]];
            y = rk[be[y]];
            if(x>y)swap(x,y);
            printf("%d\n",que(1,x+1,y));
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值