Codeforces Round #305 (Div. 1)E. Mike and Friends 后缀数组+RMQ+线段树
2015-05-29 14:29
597 查看
E. Mike and Friends
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercase English letters. What is double strange that a phone number can be associated with several bears!
In that country there is a rock band called CF consisting of
n bears (including Mike) numbered from 1 to
n.
Phone number of i-th member of CF is
si. May 17th is a holiday named Phone Calls day. In the last Phone Calls day, everyone called all the numbers that are substrings of his/her number (one may call some number several times). In particular,
everyone called himself (that was really strange country).
Denote as call(i, j) the number of times that
i-th member of CF called the
j-th member of CF.
The geek Mike has q questions that he wants to ask you. In each question he gives you numbers
l, r and k and you should tell him the number
Input
The first line of input contains integers n and
q (1 ≤ n ≤ 2 × 105 and
1 ≤ q ≤ 5 × 105).
The next n lines contain the phone numbers,
i-th line contains a string
si consisting of lowercase English letters (
).
The next q lines contain the information about the questions, each of them contains integers
l, r and k (1 ≤ l ≤ r ≤ n and
1 ≤ k ≤ n).
Output
Print the answer for each question in a separate line.
Sample test(s)
Input
Output
参考自:/article/1972582.html
思路:将字符串拼接起来,求一次后缀数组,求后缀数组时保存每个字符属于哪个串,每个串的起始位置,然后我们以sa数组作为下标建立线段树,线段树每个节点代表的区间,保存这个区间内每个字符属于哪个串,然后排序
对于一个询问包含的串K,找到K的起点在sa上的位置,我们可以二分其在sa数组上能延伸的最左端点以及最右端点,使得这之间的所有串与K的lcp都大于等于K的串长。然后我们只要在线段树内统计编号大于等于i且小于等于j的数个数就好了,这个我们只要在每个被完全包含的区间内二分答案,然后累加即可。
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercase English letters. What is double strange that a phone number can be associated with several bears!
In that country there is a rock band called CF consisting of
n bears (including Mike) numbered from 1 to
n.
Phone number of i-th member of CF is
si. May 17th is a holiday named Phone Calls day. In the last Phone Calls day, everyone called all the numbers that are substrings of his/her number (one may call some number several times). In particular,
everyone called himself (that was really strange country).
Denote as call(i, j) the number of times that
i-th member of CF called the
j-th member of CF.
The geek Mike has q questions that he wants to ask you. In each question he gives you numbers
l, r and k and you should tell him the number
Input
The first line of input contains integers n and
q (1 ≤ n ≤ 2 × 105 and
1 ≤ q ≤ 5 × 105).
The next n lines contain the phone numbers,
i-th line contains a string
si consisting of lowercase English letters (
).
The next q lines contain the information about the questions, each of them contains integers
l, r and k (1 ≤ l ≤ r ≤ n and
1 ≤ k ≤ n).
Output
Print the answer for each question in a separate line.
Sample test(s)
Input
5 5 a ab abab ababab b 1 5 1 3 5 1 1 5 2 1 5 3 1 4 5
Output
7 5 6 3 6
参考自:/article/1972582.html
思路:将字符串拼接起来,求一次后缀数组,求后缀数组时保存每个字符属于哪个串,每个串的起始位置,然后我们以sa数组作为下标建立线段树,线段树每个节点代表的区间,保存这个区间内每个字符属于哪个串,然后排序
对于一个询问包含的串K,找到K的起点在sa上的位置,我们可以二分其在sa数组上能延伸的最左端点以及最右端点,使得这之间的所有串与K的lcp都大于等于K的串长。然后我们只要在线段树内统计编号大于等于i且小于等于j的数个数就好了,这个我们只要在每个被完全包含的区间内二分答案,然后累加即可。
#include<bits/stdc++.h> using namespace std; const int maxn=400100; const int INF=1000000000; int N,M; int sa[maxn],height[maxn],Rank[maxn],t[maxn],t2[maxn],c[maxn]; int str[maxn]; int len[maxn],id[maxn]; int belong[maxn],st[maxn]; int n; int d[maxn][20]; void build_sa(int m,int n) { int *x=t,*y=t2; for(int i=0;i<m;i++)c[i]=0; for(int i=0;i<n;i++)c[x[i]=str[i]]++; for(int i=1;i<m;i++)c[i]+=c[i-1]; for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k;i<n;i++)y[p++]=i; for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; for(int i=0;i<m;i++)c[i]=0; for(int i=0;i<n;i++)c[x[y[i]]]++; for(int i=1;i<m;i++)c[i]+=c[i-1]; for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y);p=1; x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++); if(p>=n)break; m=p; } } void getheight(int n) { int k=0; for(int i=1;i<=n;i++)Rank[sa[i]]=i; for(int i=0;i<n;i++) { if(k)k--; int j=sa[Rank[i]-1]; while(str[j+k]==str[i+k])k++; height[Rank[i]]=k; } } void initRMQ(int n) { memset(d,0,sizeof(d)); for(int i=0;i<=n;i++)d[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)<=n+1;i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } int LCP(int x,int y) { if(x>y)swap(x,y); int k=0; while((1<<(k+1))<=(y-x+1))k++; return min(d[x][k],d[y-(1<<k)+1][k]); } int getl(int l,int r,int len) { int x=r; while(l<r) { int mid=(l+r)>>1; int tmp=LCP(mid+1,x); if(tmp>=len)r=mid; else l=mid+1; } return l; } int getr(int l,int r,int len) { int x=l; while(l<r) { int mid=(r+l+1)>>1; int tmp=LCP(x+1,mid); if(tmp>=len)l=mid; else r=mid-1; } return r; } struct IntervalTree { vector<int> id[maxn<<2]; void build(int o,int l,int r) { id[o].clear(); for(int i=l;i<=r;i++) id[o].push_back(belong[sa[i]]); id[o].push_back(INF); sort(id[o].begin(),id[o].end()); if(l==r)return ; int mid=(l+r)>>1; build(o<<1,l,mid); build(o<<1|1,mid+1,r); } int query(int o,int l,int r,int q1,int q2,int x,int y) { if(q1<=l&&r<=q2) { int L=lower_bound(id[o].begin(),id[o].end(),x)-id[o].begin()-1; int R=lower_bound(id[o].begin(),id[o].end(),y+1)-id[o].begin()-1; return R-L; } int mid=(l+r)>>1; int ans=0; if(q1<=mid)ans+=query(o<<1,l,mid,q1,q2,x,y); if(q2>mid)ans+=query(o<<1|1,mid+1,r,q1,q2,x,y); return ans; } }tree; void solve() { tree.build(1,1,n); while(M--) { int x,y,k; scanf("%d%d%d",&x,&y,&k); int l=getl(1,Rank[st[k]],len[k]); int r=getr(Rank[st[k]],n,len[k]); int ans=tree.query(1,1,n,l,r,x,y); printf("%d\n",ans); } } char s[maxn]; int main() { scanf("%d%d",&N,&M); n=0; int n1=27; for(int i=1;i<=N;i++) { scanf("%s",s); len[i]=strlen(s); st[i]=n; for(int j=0;j<len[i];j++) belong =i,str[n++]=s[j]-'a'+1; belong =0; str[n++]=n1++; } str =0; build_sa(n1,n+1); getheight(n); initRMQ(n); solve(); return 0; }
相关文章推荐
- I/O流技术
- springAOP
- think in uml1
- 2015深圳白石洲科目三 西考场
- 【Android】Android单例模式及使用单例模式实现自己的HttpClient工具类
- UVA 12549 Sentry Robots 最小点集覆盖
- 在Android中访问内置SE和基于SE的卡模拟(一)
- SwipeListView 详解 实现微信,QQ等滑动删除效果
- Hibernate中HQL占位符的一点使用技巧
- 第13周项目—阅读1.2
- 公式编辑
- user、function、role
- kafka的消息发送的三种模式
- 自定义Navigation Bar的Appearance的常用方法
- PHP Directory 函数
- 黑马程序员_java基础_集合(泛型、Map)
- 线性表学习归纳总结一
- 设置SVN忽略文件和目录(三)
- 分析IPNC_RDK H264编码器输出原始码流信息
- PHP Date/Time 函数