题面

戳这里

题解

首先先把所有给出的姓名和询问全部接在一起,建出\(height\)数组。

某个串要包含整个询问串,其实就相当于某个串与询问串的\(lcp\)为询问串的长度。

而两个后缀\(Suffix_i\)和\(Suffix_j\)的\(lcp\)为\(min(height_{rank_i+1},height_{rank_i+2},...,height_{rank_j})\)。

所以和某个询问串的\(lcp==\)询问串的长度的后缀的\(rank\)肯定是连续的(往两边拓展\(Min\)肯定是单调不增的),我们可以用\(st+\)二分求出。

然后第一问就可以转化为,区间内有多少个不同的数,莫队即可。

对于第二问,我们可以对于每个点求出,有多少个区间包含它,但同时不包含在这个点前面且与它的值相同的点,先对每个区间按右端点\(sort\),然后扫过去,树状数组维护左端点即可。

#include<bits/stdc++.h>
#define For(i,x,y) for (int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (int i=(x);i>=(y);i--)
#define cross(i,k) for (int i=first[k];i;i=last[i])
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0;int ch=getchar(),f=1;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-'){f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int N = 3e5+10;
struct node{
int len,pos,id,l,r,ans;
}q[N];
int n,m,cnt,len,a[N],id[N];
inline void rd(){
n=read(),m=read();
For(i,1,n){
len=read();
For(j,1,len) a[++cnt]=read(),id[cnt]=i;
a[++cnt]=10000+2*i,len=read();
For(j,1,len) a[++cnt]=read(),id[cnt]=i;
a[++cnt]=10000+2*i+1;
}
For(i,1,m){
q[i].len=read(),q[i].pos=cnt+1,q[i].id=i;
For(j,1,q[i].len) a[++cnt]=read();
a[++cnt]=10000+2*(n+1)+i;
}
//For(i,1,cnt) printf("%6d ",a[i]);puts("");
}
int Max,sum[N],x[N],y[N],SA[N],Rank[N],height[N];
inline void Radix_Sort(int n){
Max=0;
For(i,1,n) sum[x[i]]++,Max=max(Max,x[i]);
For(i,1,Max) sum[i]+=sum[i-1];
Dow(i,n,1) SA[sum[x[y[i]]]--]=y[i];
For(i,0,Max) sum[i]=0;
}
inline void GetSA(int n){
For(i,1,n) x[i]=a[i],y[i]=i;
Radix_Sort(n);
for (int i=1,p=0;p<n;i<<=1){
p=0;
For(j,n-i+1,n) y[++p]=j;
For(j,1,n) if (SA[j]>i) y[++p]=SA[j]-i;
Radix_Sort(n),swap(x,y),x[SA[1]]=p=1;
For(j,2,n) x[SA[j]]=(y[SA[j]]==y[SA[j-1]]&&y[SA[j]+i]==y[SA[j-1]+i])?p:++p;
}
For(i,1,n) Rank[SA[i]]=i;
int now=0;
For(i,1,n){
if (Rank[i]==1) continue;now=max(now-1,0);
for (int j=SA[Rank[i]-1];j+now<=n&&i+now<=n&&a[j+now]==a[i+now];now++);
height[Rank[i]]=now;
}
//For(i,1,n) printf("%6d ",Rank[i]);puts("");
//For(i,1,cnt) printf("%6d ",height[i]);puts("");
}
int p[N],Log[N],f[N][21];
inline int Query(int l,int r){
int k=Log[r-l+1];
return min(f[l][k],f[r-p[k]+1][k]);
}
inline int Findl(int ql,int qr,int x){
int l=ql,r=qr,mid,ans=qr+1;
while (l<=r) mid=l+r>>1,(Query(mid,qr)>=x)?(r=mid-1,ans=mid):l=mid+1;
return ans;
}
inline int Findr(int ql,int qr,int x){
int l=ql,r=qr,mid,ans=ql-1;
while (l<=r) mid=l+r>>1,(Query(ql,mid)>=x)?(l=mid+1,ans=mid):r=mid-1;
return ans;
}
inline void GetQuery(int n){
For(i,1,n) Log[i]=log2(i),f[i][0]=height[i];
p[0]=1;For(i,1,Log[n]) p[i]=p[i-1]<<1;
For(j,1,Log[n])
For(i,1,n-p[j]+1) f[i][j]=min(f[i][j-1],f[i+p[j-1]][j-1]);
For(i,1,m) q[i].l=Findl(1,Rank[q[i].pos],q[i].len)-1,q[i].r=Findr(Rank[q[i].pos]+1,n,q[i].len);
//For(i,1,m) printf("%d %d %d\n",q[i].l,q[i].r,Rank[q[i].pos]);
}
int blo,ans1[N],Pos[N];
inline bool cmp(node a,node b){
if (Pos[a.l]==Pos[b.l]) return (Pos[a.l]&1)?a.r<b.r:a.r>b.r;
else return Pos[a.l]<Pos[b.l];
}
int c[N],Ans;
inline void Add(int x){
x=id[SA[x]];if (!x) return;
if (++c[x]==1) Ans++;
}
inline void Del(int x){
x=id[SA[x]];if (!x) return;
if (--c[x]==0) Ans--;
}
inline void work1(){
blo=sqrt(cnt);
For(i,1,cnt) Pos[i]=(i-1)/blo+1;
sort(q+1,q+1+m,cmp);
//For(i,1,m) printf("%d %d %d\n",q[i].l,q[i].r,q[i].id);
//printf("%d %d\n",m,cnt);
int l=q[1].l,r=q[1].r;
For(i,l,r) Add(i);
ans1[q[1].id]=Ans;
For(i,2,m){
while (l<q[i].l) Del(l++);
while (r>q[i].r) Del(r--);
while (l>q[i].l) Add(--l);
while (r<q[i].r) Add(++r);
ans1[q[i].id]=Ans;
//puts("");puts("");
//For(i,1,n) printf("%d ",ans2[i]);puts("");
}
For(i,1,m) printf("%d\n",ans1[i]);
}
int ans2[N],last[N];
struct BIT{
int c[N];
inline void Add(int x,int y){for (;x<=cnt;x+=x&(-x)) c[x]+=y;}
inline int query(int x){int ans=0;for (;x;x-=x&(-x)) ans+=c[x];return ans;}
}t;
inline bool cmp2(node a,node b){return a.r<b.r;}
inline void work2(){
sort(q+1,q+1+m,cmp2);
//For(i,1,m) printf("%d %d\n",q[i].l,q[i].r);
For(i,1,m) t.Add(q[i].l,1);
int now=1;
//For(i,1,cnt) printf("%d ",id[SA[i]]);puts("");
For(i,1,cnt){
if (!id[SA[i]]) continue;
while (q[now].r<i&&now<=m) t.Add(q[now++].l,-1);
if (now>m) break;
ans2[id[SA[i]]]+=t.query(i)-t.query(last[id[SA[i]]]),last[id[SA[i]]]=i;
}
For(i,1,n) printf("%d ",ans2[i]);
}
int main(){
rd(),GetSA(cnt),GetQuery(cnt),work1(),work2();
}

BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组的更多相关文章

  1. BZOJ 2754 [SCOI2012]喵星球上的点名 (AC自动机、树状数组)

    吐槽: 为啥很多人用AC自动机暴力跳都过了?复杂度真的对么? 做法一: AC自动机+树状数组 姓名的问题,中间加个特殊字符连起来即可. 肯定是对点名串建AC自动机(map存儿子),然后第一问就相当于问 ...

  2. luogu2336 喵星球上的点名 (SA+二分答案+树状数组)

    离散化一下然后把姓名串和询问串都放一起做SA 和bzoj3277串类似地,满足某一询问的后缀(就是和这个询问对应的后缀的LCP>=这个询问长度的后缀)的排名也是一个区间,把这个区间二分出来即可 ...

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

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

  4. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机)

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2816  Solved: 1246[Submit][Status][Discuss] Descript ...

  5. [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

    a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的 ...

  6. bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

  7. BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)

    Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...

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

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

  9. BZOJ2754 SCOI2012喵星球上的点名

    绝世好题. 正当我犹豫不决时,hzwer说:“MAP!!!” 没错这题大大的暴力,生猛的stl,贼基尔爽,,ԾㅂԾ,, 由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名, ...

随机推荐

  1. appium===浮窗无法定位的解决办法

    这个问题比较常见,而且不被重视.大多数人的解决思路是根据坐标,把它点掉. 如下图,根本无法定位出“你好”这个元素: 最后的解决办法是: 在desired_caps={}中增加, desired_cap ...

  2. python魔法函数__dict__和__getattr__的妙用

    python魔法函数__dict__和__getattr__的妙用 __dict__ __dict__是用来存储对象属性的一个字典,其键为属性名,值为属性的值. 既然__dict__是个字典那么我们就 ...

  3. 《深入理解Java虚拟机》笔记--第四章、虚拟机性能监控与故障处理工具

    主要学习并记录在命令行中操作服务器时使用的六大命令工具,可视化工具JConsole和VisualVM在开发过程中熟悉. 一.jps:虚拟机进程状况工具(JVM Process Status Tool) ...

  4. centos上Jenkins搭建

    Jenkins可以提供持续集成服务,它的运行环境(runtime)需要Tomcat和JDK 要把Jenkins让Tomcat启动服务,而Tomcat需要JDK的环境 详情配置参见: http://ww ...

  5. centos6.5 使用 rpm 安装 mysql

    从mysql网站下载mysql rpm安装包(包括server.client) 1.安装server rpm -ivh MySQL-server-5.6.19-1.el6.x86_64.rpm 强制安 ...

  6. Pylint在项目中的使用

    需求背景: Pylint 是一个 Python 代码分析工具,它分析 Python 代码中的错误,查找不符合代码风格标准和有潜在问题的代码. Pylint 是一个 Python 工具,除了平常代码分析 ...

  7. netty 基础知识

    http://my.oschina.net/bieber/blog/406799 线程模型 http://hongweiyi.com/2014/01/netty-4-x-thread-model/ h ...

  8. 2019.2.25 模拟赛T1【集训队作业2018】小Z的礼物

    T1: [集训队作业2018]小Z的礼物 我们发现我们要求的是覆盖所有集合里的元素的期望时间. 设\(t_{i,j}\)表示第一次覆盖第i行第j列的格子的时间,我们要求的是\(max\{ALL\}\) ...

  9. js对小数的操作

    1.丢弃小数部分,保留整数部分 js:parseInt(7/2) 2.向上取整,有小数就整数部分加1 js: Math.ceil(7/2) 3,四舍五入. js: Math.round(7/2) 4, ...

  10. poj1573 Robot Motion(DFS)

    题目链接 http://poj.org/problem?id=1573 题意 一个机器人在给定的迷宫中行走,在迷宫中的特定位置只能按照特定的方向行走,有两种情况:①机器人按照方向序列走出迷宫,这时输出 ...