BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)

Description

a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?  

Input

 
现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。

Output

 
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。

Sample Input

2 3
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25

Sample Output

2
1
0
1 2

解题思路:

1、AC自动机

首先,我是从来不用AC自动机的,直到看到了这道题。

Trie图构建时需要承受枚举字符集的复杂度,在匹配{a~z}时还只是一个26的常数在这道题变得不可承受。

所以就不能进行图没有儿子时的构建。

那么就是AC自动机了。

map存儿子。

vector存名字。

很少使用STL选手当场死亡。

向dalao请教map枚举元素的方法。

结果一直WA

最后才知道可能会有重复的询问QAQ拿vector存一下。

致敬hzwer学长·。

代码:

  1 #include<map>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<vector>
  5 #include<cstring>
  6 #include<algorithm>
  7 char xB[1<<15],*xS=xB,*xTT=xB;
  8 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
  9 #define isd(c) (c>='0'&&c<='9')
 10 inline int read(){
 11     char xchh;
 12     int xaa;
 13     while(xchh=getc(),!isd(xchh));(xaa=xchh-'0');
 14     while(xchh=getc(),isd(xchh))xaa=xaa*10+xchh-'0';
 15     return xaa;
 16 }
 17 using std::map;
 18 using std::queue;
 19 using std::vector;
 20 typedef unsigned int uit;
 21 struct trnt{
 22     map<int,int>ch;
 23     int fl;
 24     vector<int>fin;
 25     int vis;
 26 }tr[600000];
 27 struct idt{
 28     int la,lb;
 29     vector<int>a;
 30     vector<int>b;
 31     int ans;
 32     void Ins(void)
 33     {
 34         scanf("%d",&la);
 35         for(int i=1;i<=la;i++)
 36         {
 37             int tt;
 38             scanf("%d",&tt);
 39             a.push_back(tt);
 40         }
 41         scanf("%d",&lb);
 42         for(int i=1;i<=lb;i++)
 43         {
 44             int tt;
 45             scanf("%d",&tt);
 46             b.push_back(tt);
 47         }
 48         return ;
 49     }
 50 }cat[1000000];
 51 int num[1000000];
 52 bool usd[1000000];
 53 int n,m;
 54 int siz;
 55 int len;
 56 queue<int>Q;
 57 vector<int>hre;
 58 void Insert(int k)
 59 {
 60     int len;
 61     int c;
 62     int root=0;
 63     scanf("%d",&len);
 64     for(int i=1;i<=len;i++)
 65     {
 66         scanf("%d",&c);
 67         if(tr[root].ch.find(c)==tr[root].ch.end())
 68             tr[root].ch[c]=++siz;
 69         root=tr[root].ch[c];
 70     }
 71     tr[root].fin.push_back(k);
 72     return ;
 73 }
 74 void Build(void)
 75 {
 76     int root=0;
 77     for(map<int,int>::iterator j=tr[root].ch.begin();j!=tr[root].ch.end();j++)
 78     {
 79         int sn=j->second;
 80         tr[sn].fl=0;
 81         Q.push(sn);
 82     }
 83     while(!Q.empty())
 84     {
 85         root=Q.front();
 86         Q.pop();
 87         for(map<int,int>::iterator j=tr[root].ch.begin();j!=tr[root].ch.end();j++)
 88         {
 89             int i=j->first;
 90             int sn=j->second;
 91             int nxt=tr[root].fl;
 92             while(nxt&&tr[nxt].ch.find(i)==tr[nxt].ch.end())
 93                 nxt=tr[nxt].fl;
 94             if(tr[nxt].ch.find(i)!=tr[nxt].ch.end())
 95                 nxt=tr[nxt].ch[i];
 96             tr[sn].fl=nxt;
 97             Q.push(sn);
 98         }
 99     }
100     return;
101 }
102 void Query(int p)
103 {
104     int root;
105     root=0;
106     for(uit i=0;i<cat[p].a.size();i++)
107     {
108         int c=cat[p].a[i];
109         while(root&&tr[root].ch.find(c)==tr[root].ch.end())
110             root=tr[root].fl;
111         if(tr[root].ch.find(c)!=tr[root].ch.end())
112         {
113             root=tr[root].ch[c];
114             int nxt=root;
115             while(nxt)
116             {
117                 if(tr[nxt].vis==p)
118                     break;
119                 tr[nxt].vis=p;
120                 for(uit l=0;l<tr[nxt].fin.size();l++)
121                 {
122                     int f=tr[nxt].fin[l];
123                     if(!usd[f])
124                     {
125                         usd[f]=true;
126                         hre.push_back(f);
127                         cat[p].ans++;
128                         num[f]++;
129                     }
130                 }
131                 nxt=tr[nxt].fl;
132             }
133         }
134     }
135     root=0;
136     for(uit i=0;i<cat[p].b.size();i++)
137     {
138         int c=cat[p].b[i];
139         while(root&&tr[root].ch.find(c)==tr[root].ch.end())
140             root=tr[root].fl;
141         if(tr[root].ch.find(c)!=tr[root].ch.end())
142         {
143             root=tr[root].ch[c];
144             int nxt=root;
145                while(nxt)
146             {
147                 if(tr[nxt].vis==p)
148                     break;
149                 tr[nxt].vis=p;
150                 for(uit l=0;l<tr[nxt].fin.size();l++)
151                 {
152                     int f=tr[nxt].fin[l];
153                     if(!usd[f])
154                     {
155                         usd[f]=true;
156                         hre.push_back(f);
157                         cat[p].ans++;
158                         num[f]++;
159                     }
160                 }
161                 nxt=tr[nxt].fl;
162             }
163         }
164     }
165     for(uit i=0;i<hre.size();i++)
166         usd[hre[i]]=false;
167        hre.clear();
168     return ;
169 }
170 int main()
171 {
172     scanf("%d%d",&n,&m);
173     for(int i=1;i<=n;i++)
174         cat[i].Ins();
175     for(int i=1;i<=m;i++)
176         Insert(i);
177     Build();
178     for(int i=1;i<=n;i++)
179         Query(i);
180     for(int i=1;i<=m;i++)
181         printf("%d
",num[i]);
182     for(int i=1;i<=n;i++)
183         printf("%d ",cat[i].ans);
184     return 0;
185 }

 2.广义后缀自动机

只需要先建广义后缀自动机,在pre节点上打好标记,在查询时查询节点的标记就好了。 第二问只需在询问结束节点打标记遍历子串就好了。

代码:

  1 #include<map>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 struct sant{
  6     std::map<int,int>tranc;
  7     int len;
  8     int pre;
  9 }s[2000000];
 10 struct pnt{
 11     int wgt;
 12     int vis;
 13     int tms;
 14 }p[2000000];
 15 int cnt;
 16 int siz;
 17 int fin;
 18 int n,m;
 19 int lenfname[1000000];
 20 int lensname[100000];
 21 int str[100001];
 22 void Insert(int c)
 23 {
 24     int nwp,nwq,lsp,lsq;
 25     nwp=++siz;
 26     s[nwp].len=s[fin].len+1;
 27     for(lsp=fin;lsp&&(s[lsp].tranc.find(c)==s[lsp].tranc.end());lsp=s[lsp].pre)
 28         s[lsp].tranc[c]=nwp;
 29     if(!lsp)
 30         s[nwp].pre=1;
 31     else{
 32         lsq=s[lsp].tranc[c];
 33         if(s[lsq].len==s[lsp].len+1)
 34             s[nwp].pre=lsq;
 35         else{
 36             nwq=++siz;
 37             s[nwq]=s[lsq];
 38             s[nwq].len=s[lsp].len+1;
 39             s[nwp].pre=s[lsq].pre=nwq;
 40             while((s[lsp].tranc.find(c)!=s[lsp].tranc.end())&&s[lsp].tranc[c]==lsq)
 41             {
 42                 s[lsp].tranc[c]=nwq;
 43                 lsp=s[lsp].pre;
 44             }
 45         }
 46     }
 47     fin=nwp;
 48     return ;
 49 }
 50 void mark(int plc,int times)
 51 {
 52     if(!plc)
 53         return ;
 54     if(p[plc].vis==times)
 55         return ;
 56     p[plc].vis=times;
 57     p[plc].wgt++;
 58     mark(s[plc].pre,times);
 59     return ;
 60 }
 61 int take(int plc,int times)
 62 {
 63     if(!plc)
 64         return 0;
 65     if(p[plc].vis==times)
 66         return 0;
 67     p[plc].vis=times;
 68     return p[plc].tms+take(s[plc].pre,times);
 69 }
 70 int main()
 71 {
 72     fin=++siz;
 73     scanf("%d%d",&n,&m);
 74     for(int i=1;i<=n;i++)
 75     {
 76         fin=1;
 77         scanf("%d",&lenfname[i]);
 78         for(int j=1;j<=lenfname[i];j++)
 79         {
 80             cnt++;
 81             scanf("%d",&str[cnt]);
 82             Insert(str[cnt]);
 83         }
 84         fin=1;
 85         scanf("%d",&lensname[i]);
 86         for(int j=1;j<=lensname[i];j++)
 87         {
 88             cnt++;
 89             scanf("%d",&str[cnt]);
 90             Insert(str[cnt]);
 91         }
 92     }
 93     cnt=0;
 94     for(int i=1;i<=n;i++)
 95     {
 96         int root;
 97         root=1;
 98         for(int j=1;j<=lenfname[i];j++)
 99         {
100             cnt++;
101             root=s[root].tranc[str[cnt]];
102             mark(root,i);
103         }
104         root=1;
105         for(int j=1;j<=lensname[i];j++)
106         {
107             cnt++;
108             root=s[root].tranc[str[cnt]];
109             mark(root,i);
110         }
111     }
112     for(int i=1;i<=m;i++)
113     {
114         int len;
115         int tmp;
116         scanf("%d",&len);
117         int root=1;
118         for(int j=1;j<=len;j++)
119         {
120             scanf("%d",&tmp);
121             if(!root)
122                 continue;
123             if(s[root].tranc.find(tmp)!=s[root].tranc.end())
124                 root=s[root].tranc[tmp];
125             else
126                 root=0;
127         }
128         printf("%d
",p[root].wgt);
129         p[root].tms++;
130     }
131     cnt=0;
132     for(int i=1;i<=n;i++)
133     {
134         int ans=0;
135         int root;
136         root=1;
137         for(int j=1;j<=lenfname[i];j++)
138         {
139             cnt++;
140             root=s[root].tranc[str[cnt]];
141             ans+=take(root,i+n);
142         }
143         root=1;
144         for(int j=1;j<=lensname[i];j++)
145         {
146             cnt++;
147             root=s[root].tranc[str[cnt]];
148             ans+=take(root,i+n);
149         }
150         printf("%d ",ans);
151     }
152     puts("");
153     return 0;
154 }
原文地址:https://www.cnblogs.com/blog-Dr-J/p/9681821.html