广义SAM专题的最后一题了……呼

题意:

给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_l\cdots T_r$中哪个串出现次数最多,出现了多少次。

$1\leq n,q\leq 10^5,1\leq m,\sum|T|\leq 10^4$

串中只会出现小写字母

题解:

神题啊……放图镇楼

先对T串建出广义SAM,然后把S放到上面匹配,求出每个字符所代表的节点,那么每次查询就相当于求这一段字符在SAM上对应的节点的right集合包含的字符串的众数是哪个串,显然这是parent树上的一个子树众数问题;

考虑如何维护right集合在所有$T$中的出现次数,可以对每一个节点开一棵线段树,维护每个T串的出现次数的最大值,这样子在parent树上从下往上线段树合并即可求出right集合;

把询问离线按照右端点排序,把询问标记打在parent树上,最后dfs一遍合并+处理询问即可;

口胡起来不难但是写起来……超爽!

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<cmath>
  7 #include<queue>
  8 #define inf 2147483647
  9 #define eps 1e-9
 10 using namespace std;
 11 typedef long long ll;
 12 typedef double db;
 13 struct task{
 14     int v,id;
 15     task(){v=id=0;}
 16     friend bool operator <(task a,task b){
 17         return a.v==b.v?a.id>b.id:a.v<b.v;
 18     }
 19 }ans[500001];
 20 struct qu{
 21     int l,r,ql,qr;
 22 }q[500001];
 23 struct edge{
 24     int v,next;
 25 }a[1000001];
 26 struct node{
 27     int ls,rs;
 28     task v;
 29 }t[4000001];
 30 int n,m,Q,len,ch,nw=1,tote=0,tot=1,rt=1,cnt=0,last,head[1000001],rts[1000001],son[1000001][26],fa[1000001],mx[1000001],f[1000001][20];
 31 vector<int>qrs[500001];
 32 vector<int>as[500001];
 33 char st[500001],tt[500001];
 34 void add(int u,int v){
 35     a[++tote].v=v;
 36     a[tote].next=head[u];
 37     head[u]=tote;
 38 }
 39 void updata(int &u,int l,int r,int x){
 40     if(!u)u=++cnt;
 41     if(l==r){
 42         t[u].v.v++;
 43         t[u].v.id=x;
 44         return;
 45     }
 46     int mid=(l+r)/2;
 47     if(x<=mid)updata(t[u].ls,l,mid,x);
 48     else updata(t[u].rs,mid+1,r,x);
 49     t[u].v=max(t[t[u].ls].v,t[t[u].rs].v);
 50 }
 51 void merge(int &x,int y){
 52     if(!x||!y){
 53         x|=y;
 54         return;
 55     }
 56     if(!t[x].ls&&!t[x].rs){
 57         t[x].v.v+=t[y].v.v;
 58         return;
 59     }
 60     merge(t[x].ls,t[y].ls);
 61     merge(t[x].rs,t[y].rs);
 62     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
 63 }
 64 task query(int u,int l,int r,int L,int R){
 65     if(L<=l&&r<=R){
 66         return t[u].v;
 67     }
 68     int mid=(l+r)/2;
 69     task ret;
 70     if(L<=mid)ret=max(ret,query(t[u].ls,l,mid,L,R));
 71     if(mid<R)ret=max(ret,query(t[u].rs,mid+1,r,L,R));
 72     return ret;
 73 }
 74 void extend(int ch){
 75     int p=last,np=++tot;
 76     mx[np]=mx[p]+1;
 77     for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
 78     if(!p)fa[np]=rt;
 79     else{
 80         int q=son[p][ch];
 81         if(mx[q]==mx[p]+1)fa[np]=q;
 82         else{
 83             int nq=++tot;
 84             mx[nq]=mx[p]+1;
 85             memcpy(son[nq],son[q],sizeof(son[q]));
 86             fa[nq]=fa[q];
 87             fa[q]=fa[np]=nq;
 88             for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq;
 89         }
 90     }
 91     last=np;
 92 }
 93 void dfs(int u){
 94     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
 95         int v=a[tmp].v;
 96         dfs(v);
 97         merge(rts[u],rts[v]);
 98     }
 99     for(int i=0,ii=as[u].size();i<ii;i++){
100         ans[as[u][i]]=query(rts[u],1,m,q[as[u][i]].l,q[as[u][i]].r);
101     }
102 }
103 int main(){
104     memset(head,-1,sizeof(head));
105     scanf("%s%d",st+1,&m);
106     n=strlen(st+1);
107     for(int i=1;i<=m;i++){
108         scanf("%s",tt);
109         len=strlen(tt);
110         last=rt;
111         for(int j=0;j<len;j++){
112             extend(tt[j]-'a');
113             updata(rts[last],1,m,i);
114         }
115     }
116     scanf("%d",&Q);
117     for(int i=1;i<=Q;i++){
118         scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].ql,&q[i].qr);
119         qrs[q[i].qr].push_back(i);
120     }
121     for(int i=2;i<=tot;i++){
122         f[i][0]=fa[i];
123         add(fa[i],i);
124     }
125     for(int j=1;j<=19;j++){
126         for(int i=1;i<=tot;i++){
127             f[i][j]=f[f[i][j-1]][j-1];
128         }
129     }
130     len=0;
131     for(int i=1;i<=n;i++){
132         ch=st[i]-'a';
133         for(;nw&&!son[nw][ch];)nw=fa[nw],len=mx[nw];
134         if(!nw){
135             nw=rt;
136             len=0;
137         }else{
138             nw=son[nw][ch];
139             len++;
140             for(int j=0,jj=qrs[i].size();j<jj;j++){
141                 int v=qrs[i][j];
142                 if(len>=q[v].qr-q[v].ql+1){
143                     int _nw=nw;
144                     for(int k=19;k>=0;k--){
145                         if(mx[f[_nw][k]]>=q[v].qr-q[v].ql+1){
146                             _nw=f[_nw][k];
147                         }
148                     }
149                     as[_nw].push_back(v);
150                 }
151             }
152         }
153     }
154     dfs(1);
155     for(int i=1;i<=Q;i++){
156         if(!ans[i].v)ans[i].id=q[i].l;
157         printf("%d %d\n",ans[i].id,ans[i].v);
158     }
159     return 0;
160 }

转载于:https://www.cnblogs.com/dcdcbigbig/p/10160391.html

【CF666E】Forensic Examination - 广义后缀自动机+线段树合并相关推荐

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

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

  2. Codeforces.700E.Cool Slogans(后缀自动机 线段树合并 DP)

    题目链接 \(Description\) 给定一个字符串\(s[1]\).一个字符串序列\(s[\ ]\)满足\(s[i]\)至少在\(s[i-1]\)中出现过两次(\(i\geq 2\)).求最大的 ...

  3. Codeforces 666E Forensic Examination SAM+权值线段树

    第一次做这种\(SAM\)带权值线段树合并的题 然而\(zjq\)神犇看完题一顿狂码就做出来了 \(Orz\) 首先把所有串当成一个串建\(SAM\) 我们对\(SAM\)上每个点 建一棵权值线段树 ...

  4. luoguP5108 仰望半月的夜空 [官方?]题解 后缀数组 / 后缀树 / 后缀自动机 + 线段树 / st表 + 二分...

    仰望半月的夜空 题解 可以的话,支持一下原作吧... 这道题数据很弱..... 因此各种乱搞估计都是能过的.... 算法一 暴力长度然后判断判断,复杂度\(O(n^3)\) 期望得分15分 算法二 通 ...

  5. BZOJ 3277 串 BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)...

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  6. 【NOI2018】你的名字【后缀自动机】【可持久化线段树合并】【乱搞】

    题意:给一个串 SSS,qqq 次询问,每次给定串 TTT 和 l,rl,rl,r ,求有多少个本质不同的串是 TTT 的子串而不是 Sl-rS_{l\dots r}Sl-r​ 的子串. ∣S∣≤5× ...

  7. 【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set

    题目描述 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 输入 一行一个字符串Q,表示对S的操作 如果第i个字母是小 ...

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

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

  9. UOJ #395 BZOJ 5417 Luogu P4770 [NOI2018]你的名字 (后缀自动机、线段树合并)

    NOI2019考前做NOI2018题.. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=5417 (luogu) http ...

最新文章

  1. MPB:湖南师大尹佳组-​乳酸菌对酸和胆碱盐的耐受能力
  2. python 模拟微信浏览器请求_使用Chrome修改user agent模拟微信内置浏览器
  3. 比尔盖茨,马斯克、霍金都告诉你:为什么要警惕人工智能(中)
  4. jQuery动态改变图片显示大小(修改)
  5. 曾经采集朋友圈难倒多少Python大佬,今天手把手教你如何实现!
  6. c语言第一周项目,C语言第一周实战
  7. AI学习笔记(十)卷积神经网络
  8. 笔记本电脑开机后在桌面上没有计算机图标,电脑开机之后桌面上没有图标怎么处理...
  9. 使用MNIST数据集训练出来的模型预测自己手写数据
  10. Zookeeper配置项说明
  11. linux软件包管理思维导图,推荐五款管理工具(思维导图)
  12. Java自己编名字的百家姓罗列
  13. 欧拉-拉格朗日方程(Euler -Lagrange equation)
  14. 三维重建 | 单张彩色图像三维重建学习框架
  15. 6572 Phone call分析
  16. 用百度地图进行搜索周边的建筑,医院,餐厅,学校等。
  17. 【FreeRTOS】FreeRTOS学习笔记(3)— FreeRTOS任务与协程
  18. 随机计算(3)——Stochastic Circuit Synthesis by Cube Assignment
  19. 为什么反向传播更加高效
  20. mSystem:鸟枪法宏基因组测序之外我们还能做什么

热门文章

  1. NVisionXR_iOS教程五 —— 添加灯光渲染
  2. 《OpenGL编程指南(原书第9版)》——2.3 OpenGL着色语言概述
  3. CentOS 上snmp的安装和配置
  4. 我的Java开发学习之旅------求字符串中出现次数最多的字符串以及出现的次数...
  5. debian下apr-get isntall 出错提示用apt-get -f install问题
  6. extjs 网站首页table布局,秀一下
  7. 蓝桥杯 ADV-227 算法提高 11-1实现strcmp函数
  8. L1-015. 跟奥巴马一起画方块-PAT团体程序设计天梯赛GPLT
  9. 哪个计算机无法做到双屏显示,[工具/ PC]如何在计算机上实现双屏显示?
  10. JAVA 字符串格式化-String.format()的使用(转)