题意
X是T大的一名老师,每年他都要教授许多学生基础的C++知识。在T大,每个学生在每学期的开学前都需要选课,每次选课一共分为三个阶段:预选,正选,补退选;其中”补退选”阶段最忙碌。在补退选阶段,学生即可以选课,也可以退课。
对于X老师来说,在补退选阶段可能发生以下两种事件:
1:一个姓名为S的学生选了他的课(姓名S将出现在X的已选课学生名单中)
2:一个姓名为S的学生退了他的课(姓名S将从X的已选课学生名单中移除)
同时,X老师对于有哪些学生选了他的课非常关心,所以他会不定时的查询已选课学生名单,每次查询的格式如下:
最早在哪个事件之后,姓名以S为前缀的学生数量超过了vX老师看你骨骼惊奇,所以想用这个问题考考你,你当然不会畏惧,所以勇敢的接下了这个任务。
注意1:学生的姓名可能相同,如果有p个姓名相同的学生都选了X老师的课,则他们的姓名将出现在X老师的名单上p次。
注意2:只有已经选了课的学生才会退课,如果姓名为S的学生退课,则在他退课之前X老师的名单上一定有姓名S。
注意3:选课,退课和查询都被定义为”事件”,”事件”的编号从1开始。
n<=100000,字符串长度 <= 60,输入中的所有字符串只会包含前 10 个小写字母。
强制在线。
题解
看到前缀容易想到Trie,正常的插入删除,并在每个点上开一个vector记录该前缀出现次数递增变化的时刻序列,询问时在上面二分即可。
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
char ch=gc(); int res=0,ff=1;
while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=gc(); }
while('0'<=ch&&ch<='9') res=(res<<3)+(res<<1)+ch-'0', ch=gc();
return res*ff;
}
struct node{
int cnt; vector< pair<int,int> > evt;
node* ch[10];
node(node* son=NULL){ cnt=0; evt.clear(); for(int i=0;i<=9;i++) ch[i]=son; }
} nil, *null=&nil, *root=null;
typedef node* P_node;
int Q; long long lstans;
void Insert(P_node &p,char* now,int k){
if(p==null) p=new node(null);
p->cnt++;
int len=p->evt.size();
if(len==0||p->evt[len-1].first<p->cnt) p->evt.push_back(make_pair(p->cnt,k));
if((*now)=='\000') return; Insert(p->ch[(*now)-'a'],now+1,k);
}
void Erase(P_node p,char* now){
p->cnt--;
if((*now)=='\000') return;
Erase(p->ch[(*now)-'a'],now+1);
}
int Query(P_node p,char* now,int val){
if(p==null) return -1;
if((*now)=='\000'){
int len=p->evt.size();
if(len==0||p->evt[len-1].first<val) return -1;
int L=0,R=len-1;
while(L<=R){
int mid=(L+R)>>1;
if(p->evt[mid].first==val) return p->evt[mid].second;
if(p->evt[mid].first<val) L=mid+1;
else R=mid-1;
}
}
return Query(p->ch[(*now)-'a'],now+1,val);
}
char st[65];
int main(){
freopen("bzoj4896.in","r",stdin);
freopen("bzoj4896.out","w",stdout);
Q=getint();
for(int ii=1;ii<=Q;ii++){
int pd=getint(),m=-1;
char ch=gc(); while(!('a'<=ch&&ch<='z')) ch=gc();
for(;'a'<=ch&&ch<='z';ch=gc()) st[++m]=ch; st[m+1]='\000';
if(pd==1) Insert(root,st,ii); else
if(pd==2) Erase(root,st); else
if(pd==3){
int t1=getint(),t2=getint(),t3=getint();
if(lstans==-1) lstans=1;
printf("%lld\n",lstans=Query(root,st,(lstans*t1+t2)%t3+1));
}
}
return 0;
}