AC日记——[HEOI2012]旅行问题 bzoj 2746

2746

思路:

  建立ac自动机,然后把fail树抽出来;

  然后在fail树上走lca(神奇);

代码:

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define maxn 1000005
#define mod 1000000007LL

struct TreeNodeType {
    int id;

    long long dis;

    TreeNodeType *next[26],*fail;

    TreeNodeType()
    {
        id=0,dis=0,fail=NULL;
        for(int i=0;i<26;i++) next[i]=NULL;
    }
};
struct TreeNodeType *map[maxn<<1],*que[maxn<<1],*root;

int n,m,deep[maxn<<1],f[maxn<<1],top[maxn<<1],head[maxn<<1];
int E[maxn<<2],V[maxn<<2],tot,cnt,len,size[maxn<<1];

char ch[maxn<<1];

vector<int>vec[maxn<<1];

inline void in(int &now)
{
    char Cget=getchar();now=0;
    while(Cget>‘9‘||Cget<‘0‘) Cget=getchar();
    while(Cget>=‘0‘&&Cget<=‘9‘)
    {
        now=now*10+Cget-‘0‘;
        Cget=getchar();
    }
}

void dfs1(int now,int fa)
{
    f[now]=fa,deep[now]=deep[fa]+1,size[now]=1;
    for(int i=head[now];i;i=E[i])
    {
        if(V[i]==fa) continue;
        dfs1(V[i],now),size[now]+=size[V[i]];
    }
}

void dfs2(int now,int chain)
{
    top[now]=chain;int pos=0;
    for(int i=head[now];i;i=E[i])
    {
        if(V[i]==f[now]) continue;
        if(size[V[i]]>size[pos]) pos=V[i];
    }
    if(pos) dfs2(pos,chain);else return ;
    for(int i=head[now];i;i=E[i])
    {
        if(V[i]==pos||V[i]==f[now]) continue;
        dfs2(V[i],V[i]);
    }
}

inline int lca(int x,int y)
{
    for(;top[x]!=top[y];)
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        x=f[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    return x;
}

int main()
{
    in(n);root=new TreeNodeType;
    root->id=++tot,map[root->id]=root;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ch),len=strlen(ch);
        TreeNodeType *now=root;int pos;
        for(int j=0;j<len;j++)
        {
            pos=ch[j]-‘a‘;
            if(now->next[pos]==NULL)
            {
                now->next[pos]=new TreeNodeType,now->next[pos]->id=++tot;
                map[tot]=now->next[pos],now->next[pos]->dis=(now->dis*26LL+pos)%mod;
            }
            vec[i].push_back(now->next[pos]->id),now=now->next[pos];
        }
    }
    int h=0,tail=1,u,v;que[0]=root;
    while(h<tail)
    {
        TreeNodeType *now=que[h++],*temp=NULL;
        for(int i=0;i<26;i++)
        {
            if(now->next[i]==NULL) continue;
            if(now==root) now->next[i]->fail=root;
            else
            {
                temp=now->fail;
                while(temp!=NULL)
                {
                    if(temp->next[i]!=NULL)
                    {
                        now->next[i]->fail=temp->next[i];
                        break;
                    }
                    temp=temp->fail;
                }
                if(temp==NULL) now->next[i]->fail=root;
            }
            que[tail++]=now->next[i];
            u=now->next[i]->id,v=now->next[i]->fail->id;
            E[++cnt]=head[u],V[cnt]=v,head[u]=cnt;
            E[++cnt]=head[v],V[cnt]=u,head[v]=cnt;
        }
    }
    dfs1(1,0),dfs2(1,1);
    in(m);int a,a1,b,b1;
    for(;m--;)
    {
        in(a),in(a1),in(b),in(b1);
        printf("%lld\n",map[lca(vec[a][a1-1],vec[b][b1-1])]->dis);
    }
    return 0;
}
时间: 2024-08-04 19:20:13

AC日记——[HEOI2012]旅行问题 bzoj 2746的相关文章

AC日记——[Scoi2010]序列操作 bzoj 1858

1858 思路: 恶心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 struct TreeNodeType { int l,r,l1,r1,m1,l0,r0,m0,mid,size,cnt1,cnt0; bool f1,f0,ff; inline void turn(){swap(l1,l0),swap(r1,r0),swap(m1,m0),swap(cnt1,cnt0);} inline voi

AC日记——[HNOI2008]GT考试 bzoj 1009

1009 思路: KMP上走DP(矩阵加速): DP[i][j]表示当前在第i位,同是匹配到不吉利串的第j位的方案数: 代码: #include <bits/stdc++.h> using namespace std; int mod; struct MatrixType { int n,m,ai[40][40]; void mem(int n_,int m_) { n=n_,m=m_; for(int i=0;i<=n;i++) { for(int v=0;v<=m;v++) a

AC日记——魔法少女LJJ bzoj 4399

魔法少女LJJ 思路: 动态开点权值线段树+启发式合并: 来,上代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 400005 #define maxm 7000000 int ch[maxm][2],X,dis[maxm],tot,

AC日记——[HNOI2007]紧急疏散evacuate bzoj 1189

[HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连边流量二分的答案: 如果最后流量等于人的个数,则true: 来,上代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorit

AC日记——宠物收养所 bzoj 1208

1208 思路: 一棵splay树: 如果来者是宠物且树空,就将其加入树中: 如果树不空,则查找前驱后继,取最优,然后删点: 对人亦然: 注意边界和取模,最后的ans用long long其余用int即可: 来,上代码: #include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define maxn 80005 #define mod 1000000 #define

AC日记——[NOI2006]最大获利 bzoj 1497

1497 思路: 最小割: 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 55005 #define maxm 1005005 #define INF 0x7fffffff int deep[maxn],que[maxm],F[maxm],cnt=1; int n,m,

AC日记——[SCOI2010]幸运数字 bzoj 1853

1853: [Scoi2010]幸运数字 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 2405  Solved: 887[Submit][Status][Discuss] Description 在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,

AC日记——[JSOI2007]建筑抢修 bzoj 1029

1029 思路: 贪心,而且,stl水过: 然而神特么输出que.size()就错! 代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 150005 #define ll long long struct BuildingType {

AC日记——Mato的文件管理 bzoj 3289

3289 思路: 莫队求区间逆序对个数,树状数组维护: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 50005 int bel[maxn],blo; struct QueryType { int l,r,id; bool operator<(const QueryType pos)const { if(bel[l]==bel[pos.l]) return r<pos.r; return bel[l]&