题面传送门

一道还算有点含金量的 SA 罢……

首先按照套路我们把读入的所有字符串都粘在一起,中间用分隔符隔开并建出后缀数组出来。

我们考虑对于一个固定的字符串 \(s\),什么样的字符串 \(t\) 满足 \(s\) 为 \(t\) 的子串:如果存在 \(t\) 的某个后缀 \(t'\) 使得 \(\text{LCP}(t',s)=|s|\) 那么 \(s\) 就是 \(t\) 的子串。

故我们可以想到一个很暴力的做法,枚举每个喵星人的姓/名的每一个后缀 \(suf\),如果 \(\text{LCP}(suf,s)=|s|\) 就意味着 \(s\) 在当前字符串中出现过了。

而根据 LCP Lemma,满足 \(\text{LCP}(s,t)\geq |s|\) 的 \(t\) 在后缀数组上显然对应一段区间 \([l,r]\)——这段区间可以通过二分+RMinQ 在 \(\mathcal O(n\log n)\) 的时间内求出。这个区间中每一个后缀与 \(s\) 的 LCP 长度都是 \(|s|\),也就意味着对于 \([l,r]\) 中每一个后缀对应的喵星人,它在此次点名中都会回答到。

于是此题转化为一个区间数颜色的问题——这是一个非常经典的问题,可以用莫队在 \(m\sqrt{n}\) 的时间内解决。

可是此题还有一个第二问,要求每个喵星人回答了多少次到。这其实也是一个非常套路的问题,考虑将这 \(m\) 次询问看作一个时间轴,我们将一个喵星人回答到的时间拆成一个个区间 \([l_1,r_1]\cup[l_2,r_2]\cup[l_3,r_3]\cup\dots\cup[l_m,r_m]\),那么显然这个喵星人会在时刻 \(l_i\) 被压入莫队(出现次数由 \(0\) 变为非零),在时刻 \(r_i+1\) 被弹出莫队(出现次数由非零变为 \(0\))。我们考虑利用差分的思想,当我们在 \(t\) 时刻压入一个元素时我们将其出现次数加上 \(m-t\),弹出一个元素时我们将其出现次数减去 \(m-t\),这样就能保证最终每个元素的出现次数就是所有 \(r_i-l_i+1\) 的和了。正确性显然。

时间复杂度 \(m\sqrt{n}\)(u1s1 这个数据范围有点迷惑人啊,一开始还以为莫队过不了呢)

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=5e4;
const int MAXM=1e5;
const int MAXL=4e5;
const int LOG_N=19;
int n,m,l=0,a[MAXL+5],bel[MAXL+5],sep_id=10001;pii x[MAXL+5];
int buc[MAXL+5],seq[MAXL+5],rk[MAXL+5],sa[MAXL+5],ht[MAXL+5];
int mn[MAXL+5][LOG_N+2],bg[MAXM+5],len[MAXM+5];
void getsa(){
int vmax=sep_id,gr=0;
for(int i=1;i<=l;i++) buc[a[i]]++;
for(int i=1;i<=vmax;i++) buc[i]+=buc[i-1];
for(int i=l;i;i--) sa[buc[a[i]]--]=i;
for(int i=1;i<=l;i++){
if(a[sa[i]]!=a[sa[i-1]]) gr++;
rk[sa[i]]=gr;
} vmax=gr;
for(int k=1;k<=l;k<<=1){
for(int i=1;i<=l;i++){
if(i+k<=l) x[i]=mp(rk[i],rk[i+k]);
else x[i]=mp(rk[i],0);
} memset(buc,0,sizeof(buc));gr=0;int num=0;
for(int i=l-k+1;i<=l;i++) seq[++num]=i;
for(int i=1;i<=l;i++) if(sa[i]>k) seq[++num]=sa[i]-k;
for(int i=1;i<=l;i++) buc[x[i].fi]++;
for(int i=1;i<=vmax;i++) buc[i]+=buc[i-1];
for(int i=l;i;i--) sa[buc[x[seq[i]].fi]--]=seq[i];
for(int i=1;i<=l;i++){
if(x[sa[i]]!=x[sa[i-1]]) gr++;
rk[sa[i]]=gr;
} vmax=gr;if(vmax==l) break;
}
}
void getht(){
int k=0;
for(int i=1;i<=l;i++){
if(rk[i]==1) continue;if(k) --k;
int j=sa[rk[i]-1];
while(i+k<=l&&j+k<=l&&a[i+k]==a[j+k]) k++;
ht[rk[i]]=k;
}
// for(int i=1;i<=l;i++) printf("%d\n",ht[i]);
}
int query(int x,int y){
int k=log2(y-x+1);
return min(mn[x][k],mn[y-(1<<k)+1][k]);
}
int getlcp(int x,int y){
if(x==y) return l-sa[x]+1;
if(x>y) swap(x,y);
return query(x+1,y);
}
int blk_sz,blk_cnt,lb[MAXL+5],rb[MAXL+5],bbel[MAXL+5];
struct interval{
int l,r,id;
bool operator <(const interval &rhs){
if(bbel[l]!=bbel[rhs.l]) return bbel[l]<bbel[rhs.l];
return r<rhs.r;
}
} q[MAXM+5];
int cnt[MAXN+5],num=0;
int ans[MAXM+5],ret[MAXN+5];
void push(int x,int t){
if(!x) return;
if(!cnt[x]) num++,ret[x]+=m-t+1;
cnt[x]++;
}
void pop(int x,int t){
if(!x) return;
cnt[x]--;
if(!cnt[x]) num--,ret[x]-=m-t+1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,l1,l2;i<=n;i++){
scanf("%d",&l1);
for(int j=1,x;j<=l1;j++){scanf("%d",&x);a[++l]=++x;bel[l]=i;}
a[++l]=++sep_id;scanf("%d",&l2);
for(int j=1,x;j<=l2;j++){scanf("%d",&x);a[++l]=++x;bel[l]=i;}
a[++l]=++sep_id;
}
for(int i=1;i<=m;i++){
scanf("%d",&len[i]);bg[i]=l+1;
for(int j=1,x;j<=len[i];j++){scanf("%d",&x);a[++l]=++x;}
a[++l]=++sep_id;
} getsa();getht();
for(int i=1;i<=l;i++) mn[i][0]=ht[i];
for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=l;j++)
mn[j][i]=min(mn[j][i-1],mn[j+(1<<i-1)][i-1]);
for(int i=1;i<=m;i++){
int L=1,R=rk[bg[i]],p=rk[bg[i]];
while(L<=R){
int mid=(L+R)>>1;
if(getlcp(mid,rk[bg[i]])>=len[i]) p=mid,R=mid-1;
else L=mid+1;
} q[i].l=p;
L=rk[bg[i]],R=l,p=rk[bg[i]];
while(L<=R){
int mid=(L+R)>>1;
if(getlcp(mid,rk[bg[i]])>=len[i]) p=mid,L=mid+1;
else R=mid-1;
} q[i].r=p;q[i].id=i;
// printf("%d %d\n",q[i].l,q[i].r);
}
blk_sz=(int)pow(l,0.5);blk_cnt=(l-1)/blk_sz+1;
for(int i=1;i<=blk_cnt;i++){
lb[i]=(i-1)*blk_sz+1;
rb[i]=min(i*blk_sz,l);
for(int j=lb[i];j<=rb[i];j++) bbel[j]=i;
} sort(q+1,q+m+1);
int cl=1,cr=0;
for(int i=1;i<=m;i++){//first push then pop
while(cr<q[i].r) push(bel[sa[++cr]],i);
while(cl>q[i].l) push(bel[sa[--cl]],i);
while(cr>q[i].r) pop(bel[sa[cr--]],i);
while(cl<q[i].l) pop(bel[sa[cl++]],i);
ans[q[i].id]=num;
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
for(int i=1;i<=n;i++) printf("%d%c",ret[i],(i==n)?'\n':' ');
return 0;
}

P2336 [SCOI2012]喵星球上的点名(SA+莫队)的更多相关文章

  1. BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组

    题面 戳这里 题解 首先先把所有给出的姓名和询问全部接在一起,建出\(height\)数组. 某个串要包含整个询问串,其实就相当于某个串与询问串的\(lcp\)为询问串的长度. 而两个后缀\(Suff ...

  2. 洛咕 P2336 [SCOI2012]喵星球上的点名

    洛咕 P2336 [SCOI2012]喵星球上的点名 先求出SA和height,一个点名串对应的就是一段区间,还有很多个点,就转化成了 有很多个区间,很多个点集,对每个区间计算和多少个点集有交,对每个 ...

  3. P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队+dfs序)

    P2336 [SCOI2012]喵星球上的点名 名字怎么存?显然是后缀自动机辣 询问点到多少个喵喵喵其实就是 查询后缀自动机上parent树的一个子树 于是我们考虑莫队 怎么树上莫队呢 我们用dfs序 ...

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

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

  5. Luogu P2336 [SCOI2012]喵星球上的点名

    题目链接 \(Click Here\)_ \(200\)行纯干货的代码,一发\(WA\)掉真的是让人窒息,幸好最后找到了锅在哪.(差点就要弃掉了\(QAQ\)) [调出来的时候真的是要高兴到哭出来了\ ...

  6. Luogu2336 SCOI2012 喵星球上的点名 SA、莫队

    传送门 一道很套路的题目 先将所有串拼在一起,两个不同的串之间放一个没有出现在任何串中的字符做分隔,然后SA 那么对于所有点名串能够点到的名字串在SA中对应一段区间 把这些区间拿出来然后莫队统计每一个 ...

  7. 洛谷P2336 [SCOI2012]喵星球上的点名(后缀数组+莫队)

    我学AC自动机的时候就看到了这题,想用AC自动机结果被学长码风劝退-- 学后缀数组时又看到了这题--那就写写后缀数组做法吧 结果码风貌似比当年劝退我的学长还毒瘤啊 对所有的模式串+询问串,不同串之间用 ...

  8. BZOJ2754: [SCOI2012]喵星球上的点名

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 680  Solved: 314[Submit][Sta ...

  9. BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][St ...

随机推荐

  1. for...of 和 for...in 是否可以直接遍历对象,有什么解决方案

    答案: for...of不能直接遍历对象,for  in可以直接遍历对象 原因: for...of需要实现iterator接口,对象没有实现iterator接口 解决: const obj = {a: ...

  2. 经典论文系列 | 缩小Anchor-based和Anchor-free检测之间差距的方法:自适应训练样本选择

    ​  前言  本文介绍一篇CVPR2020的论文,它在paperswithcode上获得了16887星,谷歌学术上有261的引用次数. 论文主要介绍了目标检测现有的研究进展.anchor-based和 ...

  3. 【数据结构与算法Python版学习笔记】算法分析

    什么是算法分析 算法是问题解决的通用的分步的指令的聚合 算法分析主要就是从计算资源的消耗的角度来评判和比较算法. 计算资源指标 存储空间或内存 执行时间 影响算法运行时间的其他因素 分为最好.最差和平 ...

  4. Java正则中"\\\\"表示普通反斜杠

    Java中"\"用于转义字符,"\\"表示普通无转义功能的反斜杠. 如果将字符串当做正则表达式来解析,那么"\\"也有了特殊意义,它与其后的 ...

  5. logging模块二

    背景,在学习logging时总是遇到无法理解的问题,总结,尝试一下更清晰明了了,让我们开始吧! logging模块常用format格式说明 %(levelno)s: 打印日志级别的数值 %(level ...

  6. LeetCode:动态规划

    动态规划 动态规划永远的神 这部分主要是学习了 labuladong 公众号中对于动态规划的讲解 刷了些 leetcode 题,在此做一些记录,不然没几天就忘光光了 题目 这部分内容直接上题目了,解题 ...

  7. 论文解读丨表格识别模型TableMaster

    摘要:在此解决方案中把表格识别分成了四个部分:表格结构序列识别.文字检测.文字识别.单元格和文字框对齐.其中表格结构序列识别用到的模型是基于Master修改的,文字检测模型用到的是PSENet,文字识 ...

  8. UltraSoft - Alpha - Scrum Meeting 2

    Date: Apr 09th, 2020. 会议内容为完成初步的任务分工. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM.后端 继续Django tuto ...

  9. 编写POC时候的几个参考项目

    0x01. 背景 在编写pocsuite时候,会查阅大量的文件,poc利用方式. ​ 1. pocsuite是什么 Pocsuite 是由知道创宇404实验室打造的一款开源的远程漏洞测试框架.它是知道 ...

  10. Python import urllib2 ImportError: No module named 'urllib2'

    python3 import urllib2 import urllib2 ImportError: No module named 'urllib2' python3.3里面,用urllib.req ...