传送门:

解题思路:

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

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

代码超级容易写挂的。

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

倍增处理就好了。

代码:

  1. #include<cstdio>
  2. #include<vector>
  3. #include<cstring>
  4. #include<algorithm>
  5. const int N=;
  6. struct int_2{
  7. int vl;
  8. int ps;
  9. }imt;
  10. struct sant{
  11. int tranc[];
  12. int len;
  13. int pre;
  14. }s[N];
  15. struct pnt{
  16. int hd;
  17. int fa[];
  18. int rt;
  19. std::vector<int>posquery;
  20. }p[N];
  21. struct ent{
  22. int twd;
  23. int lst;
  24. }e[N];
  25. struct trnt{
  26. int ls;
  27. int rs;
  28. int_2 val;
  29. }tr[N<<];
  30. struct qnt{
  31. int l;
  32. int r;
  33. int pl;
  34. int pr;
  35. int lt;
  36. int pos;
  37. int_2 ans;
  38. void Insert(void)
  39. {
  40. scanf("%d%d%d%d",&l,&r,&pl,&pr);
  41. lt=pr-pl+;
  42. return ;
  43. }
  44. }q[N];
  45. char tmp[N];
  46. char str[N];
  47. std::vector<int>lpnt[N];
  48. int n,m,Q;
  49. int siz;
  50. int fin;
  51. int cnt;
  52. int tnt;
  53. void ade(int f,int t)
  54. {
  55. cnt++;
  56. e[cnt].twd=t;
  57. e[cnt].lst=p[f].hd;
  58. p[f].hd=cnt;
  59. return ;
  60. }
  61. int_2 max(int_2 x,int_2 y)
  62. {
  63. if(x.vl!=y.vl)
  64. return x.vl>y.vl?x:y;
  65. return x.ps<y.ps?x:y;
  66. }
  67. void pushup(int spc)
  68. {
  69. tr[spc].val=max(tr[tr[spc].ls].val,tr[tr[spc].rs].val);
  70. return ;
  71. }
  72. void update(int l,int r,int &spc,int pos)
  73. {
  74. if(!spc)
  75. spc=++tnt;
  76. if(l==r)
  77. {
  78. tr[spc].val.vl++;
  79. tr[spc].val.ps=pos;
  80. return ;
  81. }
  82. int mid=(l+r)>>;
  83. if(pos<=mid)
  84. update(l,mid,tr[spc].ls,pos);
  85. else
  86. update(mid+,r,tr[spc].rs,pos);
  87. pushup(spc);
  88. return ;
  89. }
  90. void merge(int &spc1,int spc2)
  91. {
  92. if(!spc1||!spc2)
  93. {
  94. spc1|=spc2;
  95. return ;
  96. }
  97. if(!tr[spc1].ls&&!tr[spc1].rs)
  98. {
  99. tr[spc1].val.vl+=tr[spc2].val.vl;
  100. return ;
  101. }
  102. merge(tr[spc1].ls,tr[spc2].ls);
  103. merge(tr[spc1].rs,tr[spc2].rs);
  104. pushup(spc1);
  105. return ;
  106. }
  107. int_2 query(int l,int r,int ll,int rr,int spc)
  108. {
  109. if(!spc||l>rr||ll>r)
  110. return imt;
  111. if(ll<=l&&r<=rr)
  112. return tr[spc].val;
  113. int mid=(l+r)>>;
  114. return max(query(l,mid,ll,rr,tr[spc].ls),query(mid+,r,ll,rr,tr[spc].rs));
  115. }
  116. void Insert(int c)
  117. {
  118. int nwp,nwq,lsp,lsq;
  119. nwp=++siz;
  120. s[nwp].len=s[fin].len+;
  121. for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
  122. s[lsp].tranc[c]=nwp;
  123. if(!lsp)
  124. s[nwp].pre=;
  125. else{
  126. lsq=s[lsp].tranc[c];
  127. if(s[lsq].len==s[lsp].len+)
  128. s[nwp].pre=lsq;
  129. else{
  130. nwq=++siz;
  131. s[nwq]=s[lsq];
  132. s[nwq].len=s[lsp].len+;
  133. s[nwp].pre=s[lsq].pre=nwq;
  134. while(s[lsp].tranc[c]==lsq)
  135. {
  136. s[lsp].tranc[c]=nwq;
  137. lsp=s[lsp].pre;
  138. }
  139. }
  140. }
  141. fin=nwp;
  142. return ;
  143. }
  144. void Dfs(int x)
  145. {
  146. for(int i=p[x].hd;i;i=e[i].lst)
  147. {
  148. int to=e[i].twd;
  149. Dfs(to);
  150. merge(p[x].rt,p[to].rt);
  151. }
  152. for(int i=;i<p[x].posquery.size();i++)
  153. {
  154. int h=p[x].posquery[i];
  155. q[h].ans=query(,m,q[h].l,q[h].r,p[x].rt);
  156. }
  157. return ;
  158. }
  159. int main()
  160. {
  161. scanf("%s",str+);
  162. n=strlen(str+);
  163. scanf("%d",&m);
  164. siz=;
  165. for(int i=;i<=m;i++)
  166. {
  167. fin=;
  168. scanf("%s",tmp+);
  169. int tml=strlen(tmp+);
  170. for(int j=;j<=tml;j++)
  171. {
  172. Insert(tmp[j]-'a');
  173. update(,m,p[fin].rt,i);
  174. }
  175. }
  176. for(int i=;i<=siz;i++)
  177. ade(s[i].pre,i);
  178. for(int i=;i<=siz;i++)
  179. {
  180. p[i].fa[]=s[i].pre;
  181. }
  182. for(int j=;j<=;j++){
  183. for(int i=;i<=siz;i++)
  184. {
  185. p[i].fa[j]=p[p[i].fa[j-]].fa[j-];
  186.  
  187. }
  188. }
  189. scanf("%d",&Q);
  190. for(int i=;i<=Q;i++)
  191. {
  192. q[i].Insert();
  193. lpnt[q[i].pr].push_back(i);
  194. }
  195. int root=;
  196. int lth=;
  197. for(int i=;i<=n;i++)
  198. {
  199. int c=str[i]-'a';
  200. while(root&&!s[root].tranc[c])
  201. {
  202. root=s[root].pre;
  203. lth=s[root].len;
  204. }
  205. if(!root)
  206. {
  207. root=;
  208. lth=;
  209. continue;
  210. }
  211. root=s[root].tranc[c];
  212. lth++;
  213. for(int j=;j<lpnt[i].size();j++)
  214. {
  215. int h=lpnt[i][j];
  216. int o=root;
  217. if(lth<q[h].lt)
  218. continue;
  219. for(int k=;k>=;k--)
  220. {
  221. int nxt=p[o].fa[k];
  222. if(s[nxt].len>=q[h].lt)
  223. o=nxt;
  224. }
  225. p[o].posquery.push_back(h);
  226. q[h].pos=o;
  227. }
  228. }
  229. Dfs();
  230. for(int i=;i<=Q;i++)
  231. {
  232. if(q[i].ans.vl==)
  233. q[i].ans.ps=q[i].l;
  234. printf("%d %d\n",q[i].ans.ps,q[i].ans.vl);
  235. }
  236. return ;
  237. }

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. sql暂时表的创建

    create table #simple  /*仅仅对当前用户有效.其它用户无法使用,断掉连接后马上销毁该表*/ ( id int not null ) select * from #simple c ...

  2. F - Humidex(1.4.2)

    Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Descr ...

  3. LeetCode -- 最大连续乘积子序列

    问题描写叙述: 给定数组,找出连续乘积最大值的子序列.比如 0,-1,-3.-2.则最大连续乘积为6= (-3) * (-2) 实现思路此题与最大连续和的子序列问题相似,也可通过找到递推公式然后用DP ...

  4. windows linux 双系统默认启动windows 的几种方法

    装了双系统后,在开机时总会有想让一个系统默认启动的时候,一般安装完Ubuntu和XP双系统后,开机时默认的是启动Ubuntu系统,可是当想让XP作为默认启动的系统时怎么办呢? 在早期的Ubuntu系统 ...

  5. JAVA 解析复杂的json字符串

    转自:https://blog.csdn.net/lovelovelovelovelo/article/details/73614473String parameter = { success : 0 ...

  6. Spring Security Architecture--官方

    原文地址:https://spring.io/guides/topicals/spring-security-architecture/ Table of contents Authenticatio ...

  7. ivms4200 远程桌面访问测试过程及问题汇总

    17.11.4 测试存储服务器配置后能否自动录像确认 10:34   4200客户端关闭 10:40  打开4200客户端软件 10:51   关机 10:56  开机,有提示出现,“防火墙阻止... ...

  8. weex入门(一)

    emmmm其实没有接触过weex ,了解一番发现有很多坑,有很多基于weex改良后的框架,比如weexplus等等,基本不用踩多少坑.经过几天的深思熟虑我觉得还是去踩坑,毕竟踩完坑才能真正的了解嘛 w ...

  9. Centos7.6下安装Python3.7

    前言 话说不会开发的运维不是一个好的DBA,所以我要开始学习python了,写博客记录一下我的学习过程,另外别欺负我新来的,那个每天更博的技术流ken是我哥. 不说了,时间宝贵,开整. 1.首先来看一 ...

  10. Tomcat 的三种高级运行模式

    Tomcat 的连接器有两种:HTTP和AJP AJP(Apache JServ Protocol):AJP是面向数据包的基于TCP/IP的协议,它在Apache和Tomcat的实例之间提供了一个专用 ...