Codeforces 666E Forensic Examination
题意:给定主串s和m个模式串,每次询问[l,r]的模式串中出现s[pl...pr]次数最多的串和次数。
这题挺简单的,先把所有模式串拿来建广义后缀自动机,询问相当于子树众数,用线段树合并即可。
那我为什么写这题题解呢?
1.作为我博客第一道非BZOJ题。
2.作为我博客第一道写题意(英文)的题。
3.这题是老师留的作业,所以可以骗访问量。
4.记录一下广义后缀自动机的优秀写法,以前我是无脑建的。
- #include <cstdio>
- #include <algorithm>
- using namespace std;
- #define l(x) t[x].l
- #define r(x) t[x].r
- #define M ((L+R)>>1)
- typedef pair<int,int> pr;
- const int S=,N=;
- char s[N],sr[S];
- int m,e,q,l1,r1,l2,r2,ls,sz,tt,po[S],ln[S],l[N],f[N],ch[N][],hd[N],nx[N],to[N],rt[N],fa[N][];
- struct nd {int l,r; pr p;}t[N*];
- void ad(int x,int y) {to[++e]=y,nx[e]=hd[x],hd[x]=e;}
- void ins(int c) {
- int u=ls,x=ch[u][c];
- if(x) {
- if(l[u]+==l[x]) {ls=x; return;}
- l[++sz]=l[u]+,f[sz]=f[x],f[x]=sz,ls=sz;
- for(int j=;j<;j++) ch[sz][j]=ch[x][j];
- for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz;
- if(ch[u][c]==x) ch[u][c]=sz;
- } else {
- for(ls=++sz,l[sz]=l[u]+;u&&!ch[u][c];u=f[u]) ch[u][c]=sz;
- int x=ch[u][c];
- if(!x) {ch[u][c]=sz; return;}
- if(l[u]+==l[x]) {f[sz]=x; return;}
- l[++sz]=l[u]+,f[sz]=f[x],f[x]=f[ls]=sz;
- for(int j=;j<;j++) ch[sz][j]=ch[x][j];
- for(;u&&ch[u][c]==x;u=f[u]) ch[u][c]=sz;
- if(ch[u][c]==x) ch[u][c]=sz;
- }
- }
- void pu(int x) {t[x].p=max(t[l(x)].p,t[r(x)].p);}
- int mrg(int x,int y,int L=,int R=m) {
- if(!x||!y) return x|y;
- int z=++tt;
- if(L==R) {t[z].p=make_pair(t[x].p.first+t[y].p.first,-L); return z;}
- l(z)=mrg(l(x),l(y),L,M),r(z)=mrg(r(x),r(y),M+,R),pu(z);
- return z;
- }
- void upd(int &x,int v,int L=,int R=m) {
- if(!x) x=++tt;
- if(L==R) {t[x].p=make_pair(t[x].p.first+,-v); return;}
- if(v<=M) upd(l(x),v,L,M); else upd(r(x),v,M+,R);
- pu(x);
- }
- pr qr(int x,int l,int r,int L=,int R=m) {
- if(!x) return make_pair(,);
- if(l<=L&&r>=R) return t[x].p;
- if(r<=M) return qr(l(x),l,r,L,M); if(l>M) return qr(r(x),l,r,M+,R);
- return max(qr(l(x),l,r,L,M),qr(r(x),l,r,M+,R));
- }
- int gt(int x,int ln) {for(int i=;~i;i--) if(l[fa[x][i]]>=ln) x=fa[x][i]; return x;}
- void dfs(int x) {for(int i=hd[x];i;i=nx[i]) dfs(to[i]),rt[x]=mrg(rt[x],rt[to[i]]),fa[to[i]][]=x;}
- int main() {
- scanf("%s%d",sr,&m);
- for(int i=;i<=m;i++) {
- scanf("%s",s),ls=;
- for(int j=;s[j];j++) ins(s[j]-'a'),upd(rt[ls],i);
- }
- for(int i=,u=,s=;sr[i];i++) {
- int c=sr[i]-'a';
- while(u&&!ch[u][c]) u=f[u],s=l[u];
- if(ch[u][c]) ln[i+]=++s,u=ch[u][c],po[i+]=u;
- }
- for(int i=;i<=sz;i++) ad(f[i],i);
- dfs(),scanf("%d",&q);
- for(int j=;j<;j++) for(int i=;i<=sz;i++) fa[i][j]=fa[fa[i][j-]][j-];
- while(q--) {
- scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
- if(ln[r2]<r2-l2+) {printf("%d 0\n",l1); continue;}
- pr k=qr(rt[gt(po[r2],r2-l2+)],l1,r1);
- if(k.first) printf("%d %d\n",-k.second,k.first); else printf("%d 0\n",l1);
- }
- return ;
- }
Codeforces 666E Forensic Examination的更多相关文章
- Codeforces 666E Forensic Examination SAM or SA+线段树合并
E. Forensic Examination http://codeforces.com/problemset/problem/666/E 题目大意:给模式串S以及m个特殊串,q个询问,询问S的子串 ...
- Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)
题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...
- Codeforces 666E Forensic Examination SAM+权值线段树
第一次做这种$SAM$带权值线段树合并的题 然而$zjq$神犇看完题一顿狂码就做出来了 $Orz$ 首先把所有串当成一个串建$SAM$ 我们对$SAM$上每个点 建一棵权值线段树 每个叶子节点表示一个 ...
- codeforces 666E. Forensic Examination(广义后缀自动机,Parent树,线段树合并)
传送门: 解题思路: 很坑的一道题,需要离线处理,假如只有一组询问,那么就可以直接将endpos集合直接累加输出就好了. 这里就要将询问挂在树节点上,在进行线段树合并时查询就好了. 代码超级容易写挂的 ...
- CodeForces - 666E: Forensic Examination (广义SAM 线段树合并)
题意:给定字符串S,然后M个字符串T.Q次询问,每次给出(L,R,l,r),问S[l,r]在L到R这些T字符串中,在哪个串出现最多,以及次数. 思路:把所有串建立SAM,然后可以通过倍增走到[l,r] ...
- Codeforces 666E Forensic Examination(广义后缀自动机+线段树合并)
将所有串(包括S)放一块建SAM.对于询问,倍增定位出该子串所在节点,然后要查询的就是该子串在区间内的哪个字符串出现最多.可以线段树合并求出该节点在每个字符串中的出现次数. #include<b ...
- CF 666E Forensic Examination 【SAM 倍增 线段树合并】
CF 666E Forensic Examination 题意: 给出一个串\(s\)和\(n\)个串\(t_i\),\(q\)次询问,每次询问串\(s\)的子串\(s[p_l:p_r]\)在串\(t ...
- CF 666E Forensic Examination——广义后缀自动机+线段树合并
题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...
- [CF 666E] Forensic Examination
Description 传送门 Solution 对 \(T[1..m]\) 建立广义后缀自动机,离线,找出代表 \(S[pl,pr]\) 的每个节点,线段树合并. Code #include < ...
随机推荐
- Spring邮件发送1
注意:邮件发送code中,邮件服务器的申请和配置是比较主要的一个环节,博主这里用的是QQ的邮件服务器.有需要的可以谷歌.百度查下如何开通. 今天看了下Spring的官方文档的邮件发送这一章节.在这里记 ...
- LeetCode & 118-Pascal's Triangle-Easy
Array Description: Given numRows, generate the first numRows of Pascal's triangle. For example, give ...
- 如何用UPA优化性能?先读懂这份报告!
一.概述 打开一份UPA报告时,最先看到的就是概述页面,这也是我们推荐用户第一时间关注的页面.概述页面一开始会列出测试的基本信息,并根据腾讯游戏的性能标准,给出本次测试的结果(通过,不通过和警告): ...
- PHP常用函数集合
PHP常用函数总结 数学函数 1.abs(): 求绝对值 $abs = abs(-4.2); //4.2 数字绝对值数字 2.ceil(): 进一法取整 echo ceil(9.999); // 10 ...
- Nginx原理和配置总结
一:前言 Nginx是一款优秀的HTTP服务器和反向代理服务器,除却网上说的效率高之类的优点,个人的切身体会是Nginx配置确实简单而且还好理解,和redis差不多,比rabbitmq好理解太多了: ...
- 新概念英语(1-135)The latest report
Lesson 135 The latest report 最新消息 Listen to the tape then answer this question. Is Karen Marsh going ...
- python实现 字符串匹配函数
通配符是 shell 命令中的重要功能,? 表示匹配任意 1 个字符,*表示匹配 0 个或多个字符.请使用你熟悉的编程语言实现一个字符串匹配函数,支持 ? 和 * 通配符.如 "a?cd*d ...
- django的模型类管理器-----------数据库操作的封装
模型实例方法 str():在将对象转换成字符串时会被调用. save():将模型对象保存到数据表中,ORM框架会转换成对应的insert或update语句. delete():将模型对象从数据表中删除 ...
- 南京邮电大学java程序设计作业在线编程第二次作业
王利国的"Java语言程序设计第2次作业(2018)"详细 作业结果详细 总分:100 选择题得分:60 1. 表达式9==8&&3<7的运算结果是( ) ...
- Linux下C语言socket通信实现发送读取的文件内容--简单实现代码
本次代码涉及到的内容:socket通讯,文件读取 读取的文件以及文件位置: 要读取的文件和c文件在同一个目录下.客户端(client)读取的是123.xml,服务端(server)读取的是23.xml ...