【BZOJ2754】[SCOI2012] 喵星球上的点名(后缀数组+莫队)
大致题意: 每个人的名字由姓和名构成,如果某次点名点到的字符串是某人姓或名的一个子串,则这个人就被点到了。求每次点名被点到的人的个数及每个人被点到的总次数。
后缀数组+莫队
这道题做法很多,可以用各种神仙自动机乱搞,也可以用后缀数组+莫队一起做。
像我这么弱,什么自动机都不会,自然选择后面一种方法啦。
后缀排序预处理
首先我们要用一个后缀数组题常用的技巧,即将所有人的姓和名全部拼在一起,同时用\(p\)数组存储每个字符是属于哪一个人的。
然后便是一遍后缀排序,求出\(SA\)数组。
莫队
然后,我们要考虑如何莫队。
考虑对于给定的字符串,它所对应的后缀在\(SA\)数组中肯定是一段连续的区间。
则不难想到每次在\(SA\)数组中二分出合法的后缀。
然后在\(SA\)数组上莫队即可。
- 对于求每次被点到名的人的个数,可以开一个变量,更新有多少个后缀出现。
- 对于每个人被点到的总次数,假设当前还剩下\(k\)个询问,则对于增加操作,我们将\(tot_i+=k\),反之,将\(tot_i-=k\),即可求出答案。
具体实现详见代码。
代码
#include<bits/stdc++.h>
#define N 50000
#define M 100000
#define Len 200000
#define MAX 10000
using namespace std;
int n,len,query_tot,s[Len+5],p[Len+5];
class Class_FIO
{
private:
#define Fsize 100000
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
#define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
public:
Class_FIO() {A=B=Fin;}
inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
inline void write(int x) {if(!x) return pc('0');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
inline void writec(char x) {pc(x);}
inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
}F;
class Class_CaptainMotao//莫队
{
private:
#define Add(x) (!cnt[p[t=x]]++&&(++res,tot[p[t]]+=query_cnt-i+1))//增加一个元素
#define Del(x) (!--cnt[p[t=x]]&&(--res,tot[p[t]]-=query_cnt-i+1))//删除一个元素
int block_size,ans[M+5],tot[N+5],cnt[N+5];//ans存储询问答案,tot存储每个人被点到的次数
struct Query
{
int l,r,pos,bl;
Query(int x=0,int y=0,int p=0,int b=0):l(x),r(y),pos(p),bl(b){}
inline friend bool operator < (Query x,Query y) {return x.bl^y.bl?x.bl<y.bl:(x.bl&1?x.r<y.r:x.r>y.r);}
}q[M+5];
class Class_SuffixArray//后缀数组
{
private:
int rk[Len+5],pos[Len+5],tot[Len+5];
inline void RadixSort(int S)
{
register int i;
for(i=0;i<=S;++i) tot[i]=0;
for(i=1;i<=len;++i) ++tot[rk[i]];
for(i=1;i<=S;++i) tot[i]+=tot[i-1];
for(i=len;i;--i) SA[tot[rk[pos[i]]]--]=pos[i];
}
public:
int SA[Len+5];
inline void Init(int len,int *s)
{
register int i,k,Size=Len,cnt=0;
for(i=1;i<=len;++i) rk[pos[i]=i]=s[i];
for(RadixSort(Size),k=1;cnt<len;k<<=1)
{
for(Size=cnt,cnt=0,i=1;i<=k;++i) pos[++cnt]=len-k+i;
for(i=1;i<=len;++i) SA[i]>k&&(pos[++cnt]=SA[i]-k);
for(RadixSort(Size),i=1;i<=len;++i) pos[i]=rk[i];
for(rk[SA[1]]=cnt=1,i=2;i<=len;++i) rk[SA[i]]=(pos[SA[i-1]]^pos[SA[i]]||pos[SA[i-1]+k]^pos[SA[i]+k])?++cnt:cnt;
}
}
}S;
public:
inline void Solve()
{
register int i,j,query_cnt=0,x,y,l,r;
for(S.Init(len,s),block_size=sqrt(len),i=1;i<=query_tot;++i)
{
for(l=1,r=len,F.read(x),j=1;j<=x;++j)//每次在SA数组中二分出合法区间
{
register int tl=l,tr=r,mid=tl+tr>>1;
for(F.read(y);tl<=tr;mid=tl+tr>>1)
s[S.SA[mid]+j-1]<y?tl=mid+1:tr=mid-1;
for(mid=(l=tl)+(tr=r)>>1;tl<=tr;mid=tl+tr>>1)
s[S.SA[mid]+j-1]<=y?tl=mid+1:tr=mid-1;
r=tr;
}
l<=r&&(q[++query_cnt]=Query(l,r,i,(l-1)/block_size+1),0);//如果区间左边界小于右边界,则增加该询问
}
register int t,L=1,R=0,res=0;
for(sort(q+1,q+query_cnt+1),i=1;i<=query_cnt;++i)//莫队处理询问
{
while(R<q[i].r) Add(S.SA[++R]);while(L>q[i].l) Add(S.SA[--L]);while(R>q[i].r) Del(S.SA[R--]);while(L<q[i].l) Del(S.SA[L++]);
ans[q[i].pos]=res;
}
for(i=1;i<=query_tot;++i) F.write(ans[i]),F.writec('\n');//输出答案
for(i=1;i<=n;++i) F.write(tot[i]),F.writec(' ');//输出答案
}
}C;
int main()
{
register int i,j,x,cnt=0;
for(F.read(n),F.read(query_tot),i=1;i<=n;++i)
{
for(++cnt,F.read(x),j=1;j<=x;++j) F.read(s[++len]),p[len]=cnt;s[++len]=MAX+(cnt<<1)-1;//读入拼接字符串
for(F.read(x),j=1;j<=x;++j) F.read(s[++len]),p[len]=cnt;s[++len]=MAX+(cnt<<1);//读入拼接字符串
}
return C.Solve(),F.clear(),0;
}
【BZOJ2754】[SCOI2012] 喵星球上的点名(后缀数组+莫队)的更多相关文章
- BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1906 Solved: 839[Submit][St ...
- P2336 [SCOI2012]喵星球上的点名(SA+莫队)
题面传送门 一道还算有点含金量的 SA 罢-- 首先按照套路我们把读入的所有字符串都粘在一起,中间用分隔符隔开并建出后缀数组出来. 我们考虑对于一个固定的字符串 \(s\),什么样的字符串 \(t\) ...
- Luogu2336 SCOI2012 喵星球上的点名 SA、莫队
传送门 一道很套路的题目 先将所有串拼在一起,两个不同的串之间放一个没有出现在任何串中的字符做分隔,然后SA 那么对于所有点名串能够点到的名字串在SA中对应一段区间 把这些区间拿出来然后莫队统计每一个 ...
- BZOJ2754: [SCOI2012]喵星球上的点名
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 680 Solved: 314[Submit][Sta ...
- BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组 树状数组
2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2068 Solved: 907[Submit][St ...
- [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组
a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的 ...
- bzoj2754:[SCOI2012]喵星球上的点名(后缀自动机)
Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...
- BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机/后缀自动机)
Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串 ...
- BZOJ2754: [SCOI2012]喵星球上的点名(AC自动机)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2816 Solved: 1246[Submit][Status][Discuss] Descript ...
- BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组
题面 戳这里 题解 首先先把所有给出的姓名和询问全部接在一起,建出\(height\)数组. 某个串要包含整个询问串,其实就相当于某个串与询问串的\(lcp\)为询问串的长度. 而两个后缀\(Suff ...
随机推荐
- 22. Generate Parentheses (recursion algorithm)
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- 解决Navicat无法连接到Mysql
Navicat无法连接到Mysql,返回的错误码是Lost connection to MySQL server at ‘reading initial communication packet’, ...
- java中pojo对象首字母大写导致无法赋值问题
命名规范(文末附有java命名规范)中指出,属性变量命名应采用驼峰命名的方式,即首字母小写,其他单词首字母大写: 但有时候我们对接三方的接口时,想要封装实体类来接受,但是发现接收到的参数的变量首字母是 ...
- maven项目打包分析及打包后war包缺少配置文件报错的原因分析,使用progard混淆时配置分析
1.maven打包: 一直以来我都没太注意过在myeclipse下使用run as来clean居然对项目的target目录没有进行操作,要让操作有效,需要进入到maven build...选项下,进行 ...
- 运算符优先级 (JavaScript)
运算符优先级描述了在计算表达式时执行运算的顺序.先执行具有较高优先级的运算,然后执行较低优先级的运算.例如,先执行相乘,再执行相加. JavaScript 运算符 下表列出了 JavaScri ...
- 华东交通大学2017年ACM“双基”程序设计竞赛 1003
Problem Description 有两个球在长度为L的直线跑道上运动,两端为墙.0时刻小球a以1m/s的速度从起点向终点运动,t时刻小球b以相同的速度从终点向起点运动.问T时刻两球的距离.这里小 ...
- 统计分析: 跨库多表join
mysql中如果多个库在一个实例上, 可以进行多表的跨库Join, 但是如果后期数据库分隔到不同的实例机器上,有查询问题 mysql的查询优化器没有其他商业数据库做的好, 用来CRUD还行, 但是做大 ...
- jquery——动画
1.通过animate方法可以设置元素某属性值上的动画 <!DOCTYPE html> <html lang="en"> <head> < ...
- bootstrap栅格系统的实现
bootstrap提供了一个非常实用的栅格系统,可以实现响应式的网格布局,原理其实很简单,利用了float.百分比的宽度和@media的配合实现响应式,bootstrap默认把一行分为了12列,提供了 ...
- C. Glass Carving 正着做或者倒着做都可以
http://codeforces.com/problemset/problem/527/C 这题总体思路就是,每画一条线,然后就找到x间距的最max值和y间距的最max值,相乘就是当前的ans 那么 ...