hdu5790-数据结构-主席树-LHEISSR
思路:首先前缀是否出现可以用字典树维护。如果没有强制在线,将询问按照右端点排序,现在只需要维护右边界相同左边界不同的区间的不同前缀的个数。用一棵线段树维护从i到当前处理询问的右边界的不同前缀个数。线段树上的一个叶子节点i即表示(i,R)的不同前缀个数。若新加入一个已有前缀只需要知道前一个前缀的位置a,将(a+1,R)的答案全加一即可。现在强制在线,用主席树维护即可。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
using namespace std;
#define maxl (100100)
#define Mid(l,r) (l+(r-l)/2)
struct STR{int sl,sr,ge;}str[maxl*30];
struct Trie{int go[26],t;}trie[maxl];
int rt[maxl];
int n,ps,pt;
char st[maxl];
void str_build(int l,int r)
{
int c=++ps;
if (l==r) return;
str[c].sl=ps+1;
str_build(l,Mid(l,r));
str[c].sr=ps+1;
str_build(Mid(l,r)+1,r);
}
bool str_change(int w,int nl,int nr,int l,int r)
{
if(nr<l||r<nl) return 1;
int c=++ps;
str[c]=str[w];
if (l<=nl&&nr<=r)
{
str[c].ge++;
return 0;
}
str[c].sl=ps+1;
if (str_change(str[w].sl,nl,Mid(nl,nr),l,r)) str[c].sl=str[w].sl;
str[c].sr=ps+1;
if (str_change(str[w].sr,Mid(nl,nr)+1,nr,l,r)) str[c].sr=str[w].sr;
return 0;
}
int str_serach(int w,int nl,int nr,int l,int r)
{
if (nr<l||r<nl) return 0;
if (l<=nl&&nr<=r) return str[w].ge;
return str[w].ge+str_serach(str[w].sl,nl,Mid(nl,nr),l,r)+str_serach(str[w].sr,Mid(nl,nr)+1,nr,l,r);
}
void Trie_build(char *st,int t)
{
int len=strlen(st),w=0;
int last=rt[t-1];
for (int i=0;i<len;++i)
{
if (trie[w].go[st[i]-'a']==0) trie[w].go[st[i]-'a']=++pt;
w=trie[w].go[st[i]-'a'];
int c=last;
last=ps+1;
str_change(c,1,n,trie[w].t+1,t);
trie[w].t=t;
}
rt[t]=last;
}
void In(){
str_build(1,n);
rt[0]=1;
for (int i=1;i<=n;++i)
{
scanf("%s",st);
Trie_build(st,i);
}
}
void solve()
{
int m,l,r,Z=0,L,R;
scanf("%d",&m);
for (int i=1;i<=m;++i)
{
scanf("%d %d",&L,&R);
l=min((Z+L)%n,(Z+R)%n)+1;
r=max((Z+L)%n,(Z+R)%n)+1;
Z=str_serach(rt[r],1,n,l,l);
printf("%d\n",Z);
}
}
void clean()
{
ps=pt=0;
memset(rt,0,sizeof(rt));
memset(trie,0,sizeof(trie));
memset(str,0,sizeof(str));
}
int main(){
while (scanf("%d\n",&n)!=EOF){
clean();
In();
solve();
}
return 0;
}

浙公网安备 33010602011771号