题面传送门

一道还算有点含金量的 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. Less-23 preg_replace1

    Less-23: 直接跳到Less-23的原因是,Less-(11~22)均为注入点不为get方式的注入.我先把get型注入写的差不多,再回来整理关于注入点的内容. 核心语句: 查询.报错均有回显. ...

  2. [对对子队]会议记录4.10(Scrum Meeting 1)

    本次每日例会的开会时间是4月10日晚上20:00,使用腾讯会议作为开会工具. 今天已完成的工作 何瑞 ​ 工作内容:制作UI界面的指令编辑系统,已大致实现指令的衔接 ​ 相关issue:实现用户指令编 ...

  3. spring cloud config 结合 spring cloud bus实现配置自定的刷新

    在线上环境中,有时候我们希望系统中的某些配置参数在修改后,可以立即生效而不用重新启动服务.由上一节我们知道,我们可以把配置文件统一放到配置服务中进行管理,这一节我们在配置中心中整合spring clo ...

  4. js计算精确度丢失问题解决

    (function () { var calc = { /* 函数,加法函数,用来得到精确的加法结果 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精 ...

  5. hdu 1078 FatMouse and Cheese(记忆搜)

    N*N的矩阵,每个格子上有一个值. 老鼠起始在(1,1),每次只能水平着走或垂直着走.且最多只能走K步.且走到的格子里的值必须比上一次呆的格子里的值大. 问老鼠最多收集到多少值. 思路: 记忆搜好写. ...

  6. idea中的maven模块变成灰色

    问题 在使用idea的过程中,遇到其中一个maven模块变成灰色,如下所示: 解决方法 方法一 造成这个的原因可能是忽略了maven模块,可以尝试如下解决方法:在idea中maven中找到ignore ...

  7. Android 有意思的脚本(打印温度)

    https://github.com/LineageOS/android_hardware_google_pixel/blob/lineage-18.1/thermal/device.mk #!/sy ...

  8. [JS]什么是闭包?

    首先来思考一下下面的案例: function unclosure() { let count = 0 return count++ } for (let index = 0; index < 1 ...

  9. Python 爬取 房天下

    ... import requests from requests import ConnectionError from bs4 import BeautifulSoup import pymong ...

  10. Matplotlib (一)

    Matplotlib 用于 创建出版质量图标的绘图工具库 目的是为python构建一个 Matlab 式的绘图接口 import matplotlib.pyplot as plt pyplot 模块包 ...