P9196 [JOI Open 2016] 销售基因链
分析
假设题目只询问一个前缀,我们知道,将一堆字符串排序后,前缀相同的串是排在一起的,所以可以直接排序,二分出第一个和最后一个前缀相同的位置即可。
进一步的,如果有多组询问,我们可以把询问的前缀 直接放进那堆字符串里一起排序,这样前缀所在的位置往后一段区间的字符串的前缀都是该前缀,但我们还需要知道末尾,注意到题目中的字符串都是大写字母,所以字符串 一定比其他前缀为 的前缀大,所以也把 加入其中一起排序,这样我们就可以求出前缀为 的字符串所在的区间 了。
更进一步的,加上后缀的限制,我们把字符串反过来,也可以求出每个后缀对应的区间 ,假设一个非询问串在前缀排序时的位置为 ,后缀排序时的位置为 ,询问就变成了求 的点对 的个数,是个经典的二维数点问题,直接离线 树状数组即可解决。
对于排序,可以直接用 ,设字符串总长为 ,使用 的时间复杂度其实是 ,开 也能过,不必用 。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch))
{if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e5+10;
int n,m,c[N*3],ans[N];
string s[N],p[2][N];
struct Node{
int rank[2];
}a[N];
struct Que{
int l[2],r[2];
}b[N];
struct Str{
string s;
int id;
}d[N*3];
bool cmp(Str a,Str b){
return a.s==b.s?a.id>b.id:a.s<b.s;
}
vector<int>ad[N*3];
vector<pair<int,int> >q1[N*3];
void add(int x,int v){
for(;x<=n+2*m;x+=x&-x)
c[x]+=v;
}
int ask(int x){
int ans=0;
for(;x;x-=x&-x)
ans+=c[x];
return ans;
}
void reverse(string &s){
int len=s.size();
for(int i=0;i*2<len;i++)
swap(s[i],s[len-i-1]);
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++){
cin>>s[i];
d[i].s=s[i];d[i].id=i;
}
for(int i=1;i<=m;i++){
cin>>d[n+2*i-1].s>>p[1][i];
d[n+2*i-1].id=n+i;
d[n+2*i].s=d[n+2*i-1].s+"a";d[n+2*i].id=n+i;
}
sort(d+1,d+n+2*m+1,cmp);
for(int i=1,j;i<=n+2*m;i++){
if(d[i].id<=n)
a[d[i].id].rank[0]=i;
else{
j=d[i].id-n;
if(b[j].l[0])b[j].r[0]=i;
else b[j].l[0]=i;
}
}
for(int i=1;i<=n;i++){
reverse(s[i]);
d[i].s=s[i];d[i].id=i;
}
for(int i=1;i<=m;i++){
reverse(p[1][i]);
d[n+2*i-1].s=p[1][i];d[n+2*i-1].id=n+i;
d[n+2*i].s=p[1][i]+"a";d[n+2*i].id=n+i;
}
sort(d+1,d+n+2*m+1,cmp);
for(int i=1,j;i<=n+2*m;i++){
if(d[i].id<=n)
a[d[i].id].rank[1]=i;
else{
j=d[i].id-n;
if(b[j].l[1])b[j].r[1]=i;
else b[j].l[1]=i;
}
}
for(int i=1;i<=n;i++)
ad[a[i].rank[0]].push_back(i);
for(int i=1;i<=m;i++){
if(b[i].l[0]>b[i].r[0]||b[i].l[1]>b[i].r[1])continue;
q1[b[i].l[0]-1].push_back(make_pair(i,0));
q1[b[i].r[0]].push_back(make_pair(i,1));
}
for(int i=1;i<=n+2*m;i++){
for(auto j:ad[i]){
add(a[j].rank[1],1);
}
for(auto j:q1[i]){
if(j.second==0)
ans[j.first]+=ask(b[j.first].l[1]-1)-ask(b[j.first].r[1]);
else
ans[j.first]+=ask(b[j.first].r[1])-ask(b[j.first].l[1]-1);
}
}
for(int i=1;i<=m;i++){
write(ans[i]);puts("");
}
return 0;
}

浙公网安备 33010602011771号