您的位置:首页 > 其它

HDU 5059 Harry And Biological Teacher

2014-10-18 23:15 381 查看
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5069

题意:给出n个串,m个询问,每个询问(u,v),求u的一个最长后缀是v的前缀。

思路:离线。将关于u的后缀的查询放在一起,然后将u插入后缀自动机。对于每个v跑一遍即可。

struct SAM
{
SAM *son[4],*pre;
int len;
int ok;

void init()
{
clr(son,0);
pre=0;
ok=0;
}
};

SAM sam
,*head,*last;
int cnt;

void initSam()
{
head=last=&sam[0];
head->init();
cnt=1;
}

int get(char x)
{
if(x=='A') return 0;
if(x=='T') return 1;
if(x=='G') return 2;
return 3;
}

void insert(int x)
{
SAM *p=&sam[cnt++],*u=last;

p->init();

p->len=last->len+1;
last=p;
for(;u&&!u->son[x];u=u->pre) u->son[x]=p;
if(!u) p->pre=head;
else if(u->son[x]->len==u->len+1) p->pre=u->son[x];
else
{
SAM *r=&sam[cnt++],*q=u->son[x];
*r=*q; r->len=u->len+1;
p->pre=q->pre=r;
for(;u&&u->son[x]==q;u=u->pre) u->son[x]=r;
}
}

char s[N*2];
int cur;

int start
,len
;

vector<pair<int,int> > V
;

int ans
;

map<int,int> mp;

int n,m;

int main()
{
//	FFF;

while(scanf("%d%d",&n,&m)!=-1)
{
cur=0;
int i;
for(i=1;i<=n;i++)
{
scanf("%s",s+cur);
start[i]=cur;
len[i]=strlen(s+cur);
cur+=len[i]+3;
}
for(i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
V[u].pb(MP(v,i));
}

for(i=1;i<=n;i++) if(SZ(V[i])>0)
{
int j;
initSam();
for(j=start[i];s[j];j++)  insert(get(s[j]));
SAM *p=last;
while(p!=NULL) p->ok=1,p=p->pre;

mp.clear();
for(j=0;j<SZ(V[i]);j++)
{
int k=V[i][j].first;
int id=V[i][j].second;
if(mp.count(k))
{
ans[id]=mp[k];
continue;
}
SAM *p=head;
int t,tmp=0,cur=0;
for(t=start[k];s[t];t++)
{
int x=get(s[t]);
if(p->son[x])
{
cur++;
p=p->son[x];
if(p->ok) tmp=max(tmp,cur);
}
else break;
}
mp[k]=tmp;
ans[id]=tmp;
}
V[i].clear();
}
for(i=1;i<=m;i++) printf("%d\n",ans[i]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: