传送门
这题是真的秀.一眼看下去感觉AC自动机很可做,第一个问比较好处理,dfs序即可搞定,可第二问有点抽象,目前对树形结构的知识点不足以支持我解决这个问题.所以舍弃AC自动机,用SA做.
SA做法: 做法比较套路,刚接触SA算法可能不太好想. 把所有字符串(询问串+模式串)都串成一个大字符串,中间用互不相同的字符隔开. 然后对这个串求SA和Height数组.
在读入询问的时候,记录一下每个询问串的起点,求完SA和Height数组后求出每个询问串在SA数组中LCP(i,j) >= len的区间[L,R].然后第一问就变成了区间种类数问题,这是莫队模板题.第二问可以用差分做,每次加入一个新颜色的时候这个颜色的答案加上剩余询问数,删掉的时候减掉剩余询问数.
如何二分出[L,R]区间也是一个问题.由LCP Theorem的性质我们可以从询问串的起点出发,往右边和左边分别二分得到这个[L,R]区间. 这个过程需要ST表加速一下二分时候判断的过程.
这题的综合性很强,后缀数组,莫队,还有ST表,以及一些奇奇怪怪的边界问题,是个很有价值的题目.
PS:这题的两个问用树状数组离线也是可做的.
参考代码(在注释里标明了各块函数的作用).

#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>using namespace std;
const int N = 4e5+10;inline int read(){int x = 0,f=1;char ch = getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
struct Q{int l,r,id;
}q[N];// SA部分
int col[N],s[N],cnt[N],id[N],px[N],sa[N],rk[N],oldrk[N],ht[N],st[21][N],pre[N];
bool cmp(int x,int y,int w){return oldrk[x] == oldrk[y] && oldrk[x+w] == oldrk[y+w];
}
void SA(int n){int m = 3e5,p;fir(i,1,n) cnt[rk[i] = s[i]]++;fir(i,1,m) cnt[i] += cnt[i-1];afir(i,n,1) sa[cnt[rk[i]]--] = i;for(int w = 1;w < n;w <<= 1,m = p){p = 0;afir(i,n,n-w+1) id[++p] = i;fir(i,1,n) if(sa[i] > w) id[++p] = sa[i]-w;mem(cnt,0);fir(i,1,n) cnt[px[i] = rk[id[i]]]++;fir(i,1,m) cnt[i] += cnt[i-1];afir(i,n,1) sa[cnt[px[i]]--] = id[i];p = 0;swap(rk,oldrk);fir(i,1,n)rk[sa[i]] = cmp(sa[i],sa[i-1],w)?p:++p;if(p == n) break;}int k = 0;fir(i,1,n){if(k) k--;while(s[i+k] == s[sa[rk[i]-1]+k]) k++;ht[rk[i]] = k;}
}// ST表部分
void prework(int n){fir(i,0,N-1) pre[i] = log(i)/log(2);fir(i,1,n) st[0][i] = ht[i];fir(i,1,20) fir(j,1,n-(1<<i)-1) st[i][j] = min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
int lcp(int l,int r){int len = pre[r-l+1]; return min(st[len][l],st[len][r-(1<<len)+1]);
}// 莫队部分
int blo,nn,L[N],R[N],pos[N];
void build(int n){blo = sqrt(n);nn = n/blo;fir(i,1,nn){L[i] = (i-1)*blo+1;R[i] = i*blo;}if(n % blo){nn++;L[nn] = R[nn-1]+1;R[nn] = n;}fir(i,1,nn) fir(j,L[i],R[i]) pos[j] = i;
}bool c1(Q x,Q y){return pos[x.l]^pos[y.l]?pos[x.l]<pos[y.l]:x.r<y.r;
}int ans,vis[N],res[N],Ans[N],n;
void add(int x,int num){if(!vis[x] && x <= n){res[x]+=num;ans++;}vis[x]++;
}
void del(int x,int num){vis[x]--;if(!vis[x] && x <=n){res[x]-=num;ans--;}
}// 读入数据部分
int main(){int m,x,cnt=0,idd=1e4+1,ct=0;n = read();m = read();s[0] = -1e9;fir(i,1,n){int len;len = read();++ct;fir(j,1,len){s[++cnt] = read();col[cnt] = ct;}s[++cnt] = ++idd;len = read();fir(j,1,len){s[++cnt] = read();col[cnt] = ct;}s[++cnt] = ++idd;}fir(i,1,m){int len;len = read();++ct;q[i] = {cnt+1,len,i};fir(j,1,len){s[++cnt] = read();col[cnt] = ct;}s[++cnt] = ++idd;}SA(cnt);prework(cnt);fir(i,1,m){int sta = rk[q[i].l],l = sta,r = cnt+1,len = q[i].r;while(l < r){int mid = (l + r) >> 1;if(lcp(sta,mid) >= len) l = mid+1;else r = mid;}q[i].r = l-1;r = sta;l = 1;while(l < r){int mid = (l + r) >> 1;if(lcp(mid,sta) >= len) r = mid;else l = mid+1;}q[i].l = l;if(q[i].l <= q[i].r) q[i].l--;else q[i].r++;}build(cnt);sort(q+1,q+1+m,c1);int l = 1,r = 0;fir(i,1,m){int num = m-i+1;while(r < q[i].r) add(col[sa[++r]],num);while(l > q[i].l) add(col[sa[--l]],num);while(r > q[i].r) del(col[sa[r--]],num);while(l < q[i].l) del(col[sa[l++]],num);Ans[q[i].id] = ans;}fir(i,1,m) cout << Ans[i] << "\n";fir(i,1,n) cout << res[i] << " ";return 0;
}

[SCOI2012]喵星球上的点名(后缀数组+莫队+ST表)相关推荐

  1. bzoj 2754 [SCOI2012]喵星球上的点名 后缀数组+莫队

    先把所有串按顺序放到一起,两个串间加非法字符隔开,求一个后缀数组. 然后对于询问,满足条件的子串在后缀数组上一定是连续一段区间. 这个区间的左右端点可以在读入的过程中二分求. 然后这个问题变成了多组询 ...

  2. [BZOJ2754][SCOI2012]喵星球上的点名 后缀数组

    不科学啊...这题暴力可过...感觉所有串都是a就可以卡掉啊... 我的做法就是先把姓名串和询问串全部连在一起,并打上分隔符,并记录每个字符属于哪个串,求出SA.对于每个询问就从它所在的位置左右扫he ...

  3. BZOJ 2754: [SCOI2012]喵星球上的点名

    二次联通门 : BZOJ 2754: [SCOI2012]喵星球上的点名 /*BZOJ 2754: [SCOI2012]喵星球上的点名此题有N种做法...见到众dalao用各种奇怪的姿势AC此题..具 ...

  4. 【BZOJ2754】[SCOI2012]喵星球上的点名

    [BZOJ2754][SCOI2012]喵星球上的点名 题面 bzoj 洛谷 题解 这题有各种神仙做法啊,什么暴力\(AC\)自动机.\(SAM\)等等五花八门 我这个蒟蒻在这里提供一种复杂度正确且常 ...

  5. 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告

    P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...

  6. SCOI2012 喵星球上的点名 BZOJ 2754

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 2246 Solved: 975 Description ...

  7. [SCOI2012]喵星球上的点名——堪称十种方法做的题

    题意: 给你N个串对,M个询问串,对每个询问串求是多少串对的子串(在串对的某一个中作为子串),以及每个串对最终是包含了多少询问串 方法众多.. 可谓字符串家族八仙过海各显神通. 复杂度不尽相同,O(n ...

  8. 2754. [SCOI2012]喵星球上的点名【后缀数组】

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

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

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

最新文章

  1. 2022-2028年中国多肽药物市场研究及前瞻分析报告
  2. 一致性 Hash 算法的实际应用
  3. 开发日记-20190916 gradle新的依赖方式implementation,api,compileOnly
  4. Javascript创建节点
  5. 分表分库中间件 sharding-jdbc
  6. 线下活动 | 揭秘大数据背后的京东虚拟平台(免费报名中)
  7. Spring学习之Bean的配置
  8. 【落地为王】域乎区块链应用之影视文化篇:让梦想照进现实
  9. SAP Marketing cloud里的campaign管理
  10. 从Jensen不等式到Minkowski不等式
  11. CTO 要我把这份 MySQL 规范贴在工位上!
  12. 分布式光纤传感技术(DTS/BOTDA/BOTDR/光栅/OTDR)近几年会有较快的发展(本人预测)
  13. 2021年高压电工模拟考试系统及高压电工考试试题
  14. 教你同时查询安能物流多个单号的物流情况并保存
  15. WiFi语音智能家居控制系统(一)
  16. 开发过程中沟通的重要性
  17. 注册Apple ID -- 常识
  18. int类型和Integer类型数据的比较
  19. mappedBy和JoinColumn实质上指向的是同一个表即外键作为主键所在的表对应的实体
  20. 信奥题库(OI题库)8月月赛T1题解 幂次数

热门文章

  1. 美国人初学Python100个代码题目之2
  2. 【逗老师带你学IT】PRTG获取HUAWEI FusionServer iBMC传感器状态
  3. centos 安装百度云/百度网盘Python客户端
  4. i5 12400f和i3 12100f性能对比
  5. python绘制糖葫芦_冰糖葫芦怎么画
  6. 2021湖北高考成绩查询时间咋查,2021年湖北高考成绩查询具体时间,几点钟可以查询...
  7. vijosP1285 佳佳的魔法药水
  8. HA集群强制进行Active/Standby切换的命令
  9. 逻辑回归三部曲——逻辑回归项目实战(信贷数据+Python代码实现)
  10. 二级计算机11月份考试,2020年12月计算机二级考试报名时间及考试安排