传送门:

解题思路:

很坑的一道题,需要离线处理,假如只有一组询问,那么就可以直接将endpos集合直接累加输出就好了。

这里就要将询问挂在树节点上,在进行线段树合并时查询就好了。

代码超级容易写挂的。

注意要将匹配串时尽量找到最浅根,易于统计答案。

倍增处理就好了。

代码:

 #include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
const int N=;
struct int_2{
int vl;
int ps;
}imt;
struct sant{
int tranc[];
int len;
int pre;
}s[N];
struct pnt{
int hd;
int fa[];
int rt;
std::vector<int>posquery;
}p[N];
struct ent{
int twd;
int lst;
}e[N];
struct trnt{
int ls;
int rs;
int_2 val;
}tr[N<<];
struct qnt{
int l;
int r;
int pl;
int pr;
int lt;
int pos;
int_2 ans;
void Insert(void)
{
scanf("%d%d%d%d",&l,&r,&pl,&pr);
lt=pr-pl+;
return ;
}
}q[N];
char tmp[N];
char str[N];
std::vector<int>lpnt[N];
int n,m,Q;
int siz;
int fin;
int cnt;
int tnt;
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
int_2 max(int_2 x,int_2 y)
{
if(x.vl!=y.vl)
return x.vl>y.vl?x:y;
return x.ps<y.ps?x:y;
}
void pushup(int spc)
{
tr[spc].val=max(tr[tr[spc].ls].val,tr[tr[spc].rs].val);
return ;
}
void update(int l,int r,int &spc,int pos)
{
if(!spc)
spc=++tnt;
if(l==r)
{
tr[spc].val.vl++;
tr[spc].val.ps=pos;
return ;
}
int mid=(l+r)>>;
if(pos<=mid)
update(l,mid,tr[spc].ls,pos);
else
update(mid+,r,tr[spc].rs,pos);
pushup(spc);
return ;
}
void merge(int &spc1,int spc2)
{
if(!spc1||!spc2)
{
spc1|=spc2;
return ;
}
if(!tr[spc1].ls&&!tr[spc1].rs)
{
tr[spc1].val.vl+=tr[spc2].val.vl;
return ;
}
merge(tr[spc1].ls,tr[spc2].ls);
merge(tr[spc1].rs,tr[spc2].rs);
pushup(spc1);
return ;
}
int_2 query(int l,int r,int ll,int rr,int spc)
{
if(!spc||l>rr||ll>r)
return imt;
if(ll<=l&&r<=rr)
return tr[spc].val;
int mid=(l+r)>>;
return max(query(l,mid,ll,rr,tr[spc].ls),query(mid+,r,ll,rr,tr[spc].rs));
}
void Insert(int c)
{
int nwp,nwq,lsp,lsq;
nwp=++siz;
s[nwp].len=s[fin].len+;
for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
s[lsp].tranc[c]=nwp;
if(!lsp)
s[nwp].pre=;
else{
lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+)
s[nwp].pre=lsq;
else{
nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+;
s[nwp].pre=s[lsq].pre=nwq;
while(s[lsp].tranc[c]==lsq)
{
s[lsp].tranc[c]=nwq;
lsp=s[lsp].pre;
}
}
}
fin=nwp;
return ;
}
void Dfs(int x)
{
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
Dfs(to);
merge(p[x].rt,p[to].rt);
}
for(int i=;i<p[x].posquery.size();i++)
{
int h=p[x].posquery[i];
q[h].ans=query(,m,q[h].l,q[h].r,p[x].rt);
}
return ;
}
int main()
{
scanf("%s",str+);
n=strlen(str+);
scanf("%d",&m);
siz=;
for(int i=;i<=m;i++)
{
fin=;
scanf("%s",tmp+);
int tml=strlen(tmp+);
for(int j=;j<=tml;j++)
{
Insert(tmp[j]-'a');
update(,m,p[fin].rt,i);
}
}
for(int i=;i<=siz;i++)
ade(s[i].pre,i);
for(int i=;i<=siz;i++)
{
p[i].fa[]=s[i].pre;
}
for(int j=;j<=;j++){
for(int i=;i<=siz;i++)
{
p[i].fa[j]=p[p[i].fa[j-]].fa[j-]; }
}
scanf("%d",&Q);
for(int i=;i<=Q;i++)
{
q[i].Insert();
lpnt[q[i].pr].push_back(i);
}
int root=;
int lth=;
for(int i=;i<=n;i++)
{
int c=str[i]-'a';
while(root&&!s[root].tranc[c])
{
root=s[root].pre;
lth=s[root].len;
}
if(!root)
{
root=;
lth=;
continue;
}
root=s[root].tranc[c];
lth++;
for(int j=;j<lpnt[i].size();j++)
{
int h=lpnt[i][j];
int o=root;
if(lth<q[h].lt)
continue;
for(int k=;k>=;k--)
{
int nxt=p[o].fa[k];
if(s[nxt].len>=q[h].lt)
o=nxt;
}
p[o].posquery.push_back(h);
q[h].pos=o;
}
}
Dfs();
for(int i=;i<=Q;i++)
{
if(q[i].ans.vl==)
q[i].ans.ps=q[i].l;
printf("%d %d\n",q[i].ans.ps,q[i].ans.vl);
}
return ;
}

codeforces 666E. Forensic Examination(广义后缀自动机,Parent树,线段树合并)的更多相关文章

  1. 【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并

    题目描述 给出 $S$ 串和 $m$ 个 $T_i$ 串,$q$ 次询问,每次询问给出 $l$ .$r$ .$x$ .$y$ ,求 $S_{x...y}$ 在 $T_l,T_{l+1},...,T_r ...

  2. Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)

    题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...

  3. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  4. 【CF666E】Forensic Examination 广义后缀自动机+倍增+线段树合并

    [CF666E]Forensic Examination 题意:给你一个字符串s和一个字符串集合$\{t_i\}$.有q个询问,每次给出$l,r,p_l,p_r$,问$s[p_l,p_r]$在$t_l ...

  5. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  6. CF666E Forensic Examination 广义后缀自动机_线段树合并_树上倍增

    题意: 给定一个串 $S$ 和若干个串 $T_{i}$每次询问 $S[pl..pr]$ 在 $Tl..Tr$ 中出现的最多次数,以及出现次数最多的那个串的编号. 数据范围: 需要离线 题解:首先,很常 ...

  7. CodeForces - 666E: Forensic Examination (广义SAM 线段树合并)

    题意:给定字符串S,然后M个字符串T.Q次询问,每次给出(L,R,l,r),问S[l,r]在L到R这些T字符串中,在哪个串出现最多,以及次数. 思路:把所有串建立SAM,然后可以通过倍增走到[l,r] ...

  8. 【CF666E】Forensic Examination - 广义后缀自动机+线段树合并

    广义SAM专题的最后一题了……呼 题意: 给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_ ...

  9. 【CF666E】Forensic Examination(后缀自动机,线段树合并)

    [CF666E]Forensic Examination(后缀自动机,线段树合并) 题面 洛谷 CF 翻译: 给定一个串\(S\)和若干个串\(T_i\) 每次询问\(S[pl..pr]\)在\(T_ ...

  10. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

随机推荐

  1. Mysql基础部分,针对以后python使用

    #redis 非关系型数据库#mysql 关系型数据库 表与表之间有数据关系 Oracle Mysql SqlServer DB2#多张表组合在一起就是数据库#冗余 存储两倍数据 可以使系统速度更快 ...

  2. 129.C++面试一百题(1-51)

  3. Gallery滑动一页(一个Item)效果

    本文主要介绍如何使用Gallery只滑动一页以及其实现原理. Demo APK 可以方便的查看效果,在各大应用商店搜索 trinea android 下载即可,如:Google Play. 可运行代码 ...

  4. AIX 软件包结构

    AIX installp软件包结构  1. usr部分 2. / (root)部分 3. share部分    AIX 为了实现在客户机 / 服务器环境下安装的灵活性将安装包划分为 usr 部分 .r ...

  5. 原生js实现多组图片切换

    这几天一直在练习原生js写效果,需要理清自己的逻辑,做了一个切换多组图片的效果: css样式: * { margin: 0; padding: 0; } body { background: #303 ...

  6. CrawlSpider爬取读书网

    crawlspider用于定义一些规则用于提取页面符合规则的数据,然后继续爬取. 一.开始一个读书网项目 scrapy startproject 项目名称cd 项目名称/项目名称/spidersscr ...

  7. C++11 volatile 类型

    volatile作用: 作为指令关键字,确保本条指令不会受到编译器的优化而省略,而且要求每次直接读值. 定义: volatile int nTest; volatile关键字是一种类型修饰符,用它声明 ...

  8. 读MBA经历回想(下)做法决定结果——北漂18年(49)

    上期聊了目的决定了手段,这次说说详细做法决定了最后的结果. 差额面试被淘汰的高分学员 2005年,是北京邮电大学工商管理学入学考试第一个差额淘汰的年份.意思是过分数线(165分)的人数超过了录取人数, ...

  9. Dynamics CRM2013/2015 插件注冊工具登录后无法显示assembly列表问题的解决的方法

    自微软从2013版本号推出新的插件注冊器后,随着UI的重大更新后,问题也多了非常多.前面已有博客提到注冊assembly时看不到注冊button(http://blog.csdn.net/vic022 ...

  10. HDU 5281 Senior&#39;s Gun 杀怪

    题意:给出n把枪和m个怪.每把枪有一个攻击力,每一个怪有一个防御力.假设某把枪的攻击力不小于某个怪的防御力则能将怪秒杀,否则无法杀死.一把枪最多仅仅能杀一个怪,不能用多把枪杀同一个怪.每杀一次怪能够得 ...