好题啊

\(SA+ST\text{表}+\text{莫队}\)

我们先强行把所有的串连起来,串与串之间插入特殊字符,姓和名之间也插入特殊字符

之后跑一遍\(SA\),求出\(sa\)和\(het\)

对于所有的询问串,我们标记好他们的开头,之后我们对于排好序的后缀建一个\(st\)表,找到每个询问串往左往右最多可以扩展到哪里

扩展到哪里自然是这个区间内的\(het\)的最小值大于等于询问串的长度了,这个二分+\(st\)表就能做到

第一问就变成了区间数颜色了,这个套上一个莫队就可以了

第二问是求出一种颜色被数了多少次,我们在莫队的时候顺便打上一个时间戳,如果在一个询问里这个颜色第一次出现我们就标记好这个询问的时间,等到下一次这个颜色被完全删除的时候我们利用这个操作的时间做一个差就好了

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 500005
#define re register
#define LL long long
#define lowbit(x) ((x)&(-x))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
char c=getchar();re int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int tax[maxn],rk[maxn],sa[maxn],het[maxn],tp[maxn],f[maxn],S[maxn];
int to[maxn],c[maxn],St[maxn][19],logg[maxn],Ans[maxn],li[maxn],cnt[maxn];
int n,m,L,M,len,sz,ans;
inline void qsort()
{
for(re int i=0;i<=M;i++) tax[i]=0;
for(re int i=1;i<=L;i++) tax[rk[i]]++;
for(re int i=1;i<=M;i++) tax[i]+=tax[i-1];
for(re int i=L;i;--i) sa[tax[rk[tp[i]]]--]=tp[i];
}
struct Ask{int x,y,rk;} a[maxn];
inline void add(int x,int o) {if(!f[sa[x]]) return;if(!cnt[f[sa[x]]]) ++ans,c[f[sa[x]]]+=m-o+1;cnt[f[sa[x]]]++;}
inline void del(int x,int o) {if(!f[sa[x]]) return;cnt[f[sa[x]]]--;if(!cnt[f[sa[x]]]) --ans,c[f[sa[x]]]-=m-o+1;}
inline int query(int l,int r){int k=logg[r-l+1];return min(St[l][k],St[r-(1<<k)+1][k]);}
inline int cmp(Ask A,Ask B) { if(A.x/sz==B.x/sz) return A.y<B.y; return A.x<B.x;}
int main()
{
n=read(),m=read();
for(re int i=1;i<=n;i++)
{
len=read();
for(re int j=1;j<=len;j++) S[++L]=read()+1,f[L]=i; S[++L]=0;
len=read();
for(re int j=1;j<=len;j++) S[++L]=read()+1,f[L]=i; S[++L]=0;
}
for(re int i=1;i<=m;i++)
{
len=read();to[i]=L+1;li[i]=len;
for(re int j=1;j<=len;j++) S[++L]=read()+1; S[++L]=0;
}
for(re int i=1;i<=L;i++) M=max(M,S[i]);sz=M;
for(re int i=1;i<=L;i++) if(!S[i]) S[i]=++sz;
for(re int i=1;i<=L;i++) M=max(M,S[i]),rk[i]=S[i],tp[i]=i;
qsort();
for(re int w=1,p=0;p<L;M=p,w<<=1)
{
p=0;
for(re int i=1;i<=w;i++) tp[++p]=L-w+i;
for(re int i=1;i<=L;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
qsort();
for(re int i=1;i<=L;i++) std::swap(rk[i],tp[i]);
rk[sa[1]]=p=1;
for(re int i=2;i<=L;i++)
rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
}
int k=0;
for(re int i=1;i<=L;i++)
{
if(k) --k; int j=sa[rk[i]-1];
while(S[i+k]==S[j+k]) ++k; het[rk[i]]=k;
}
memset(St,20,sizeof(St));
for(re int i=1;i<=L;i++) St[i][0]=het[i];
for(re int i=2;i<=L;i++) logg[i]=1+logg[i>>1];
for(re int j=1;j<=18;j++)
for(re int i=1;i+(1<<j)-1<=L;i++)
St[i][j]=min(St[i][j-1],St[i+(1<<(j-1))][j-1]);
for(re int i=1;i<=m;i++)
{
int j=rk[to[i]];a[i].rk=i;
int l=2,r=j;
while(l<=r) {int mid=l+r>>1;if(query(mid,j)>=li[i]) a[i].x=mid-1,r=mid-1;else l=mid+1;}
if(!a[i].x) a[i].x=j;
l=j+1,r=L;
while(l<=r) {int mid=l+r>>1;if(query(j+1,mid)>=li[i]) a[i].y=mid,l=mid+1;else r=mid-1;}
if(!a[i].y) a[i].y=j;
}
sz=std::sqrt(L);
std::sort(a+1,a+m+1,cmp);
int l=0,r=0;
for(re int i=1;i<=m;i++)
{
while(l<a[i].x) del(l++,i);
while(r<a[i].y) add(++r,i);
while(l>a[i].x) add(--l,i);
while(r>a[i].y) del(r--,i);
Ans[a[i].rk]=ans;
}
for(re int i=1;i<=m;i++) printf("%d\n",Ans[i]);
for(re int i=1;i<=n;i++) printf("%d ",c[i]);
return 0;
}

【[SCOI2012]喵星球上的点名】的更多相关文章

  1. BZOJ 2754: [SCOI2012]喵星球上的点名

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

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

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

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

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

  4. BZOJ 2754: [SCOI2012]喵星球上的点名 [AC自动机+map+暴力]

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

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

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

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

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

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

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

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

    [BZOJ2754][SCOI2012]喵星球上的点名 题面 bzoj 洛谷 题解 这题有各种神仙做法啊,什么暴力\(AC\)自动机.\(SAM\)等等五花八门 我这个蒟蒻在这里提供一种复杂度正确且常 ...

  9. 2754. [SCOI2012]喵星球上的点名【后缀数组】

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

  10. SCOI2012喵星球上的点名

    http://codevs.cn/problem/2403/ 2012年省队选拔赛四川  时间限制: 2 s  空间限制: 128000 KB   题目描述 Description a180285幸运 ...

随机推荐

  1. 97 条 Linux 运维工程师常用命令总结[转]

    1.ls [选项] [目录名 | 列出相关目录下的所有目录和文件 -a 列出包括.a开头的隐藏文件的所有文件 -A 通-a,但不列出"."和".." -l 列出 ...

  2. c# 屏蔽快捷键

    前言 有时候开发会遇到这样一个需求,软件需要屏蔽用户的组合快捷键或某些按键,避免强制退出软件,防止勿操作等. 原理 1.要实现组合键,按键拦截,需要用到user32.dll中的SetWindowsHo ...

  3. python 生成、删除、拷贝目录

    1. 生成目录 函数原型:distutils.dir_util.mkpath(name[, mode=0777, verbose=0, dry_run=0]) from distutils impor ...

  4. Python 进阶

    高阶函数 定义 函数接受的参数是一个函数 函数的返回值为一个函数 满足以上2点中其中一个就是高阶函数 函数嵌套 定义 函数中def定义一个函数 嵌套会存在闭包, 其他情况不会有闭包(闭包闭的是变量) ...

  5. Java入门系列-11-类和对象

    这篇文章为你搞懂类和对象的使用 对象:用来描述客观事物的实体,由一组属性和方法组成,万物皆对象. 属性:就是对象的特征,像身高.体重.颜色 方法:对象的行为,如跑.跳 类:类是模子,定义对象将会拥有的 ...

  6. django管理界面使用与bootstrap模板使用

    一.bootstrap模板使用 1.去bootstrap官网找一个合适的模板,下载下来,右键另存为即可 bootstrap官网---->bootstrap中文文档3-------->起步- ...

  7. 模糊查询-动态参数,防SQL注入

    WHERE("title like '%'+#{keyWord}+'%'"); -MS SQL WHERE("title like concat('%',#{keyWor ...

  8. c#学习基础(2)存储、值类型和引用类型、变量

    程序运行时,它的数据必须存储在内存中,数据项需要多大的内存.存储在什么地方以及如何存储都依赖该数据项的类型 运行中的程序使用两个区域来存储数据:栈和堆 栈是一个内存数组,是一个LIFO(last in ...

  9. artDialog组件应用学习(一)

    个人觉得artDialog是一组很不错的对话框组件.写的是artDialog_v6应用. 官方称其兼容性测试通过:IE6~IE11.Chrome.Firefox.Safari.Opera. 官网:ht ...

  10. Fragment中的方法findFragmentById(int id)的返回值探讨

    在学习<Android编程权威指南>P124页的时候,遇到了这样的代码: 引起了我的疑问if的判断条件是(fragment==null),那执行完上一句 Fragment Fragment ...