bzoj 4896: [Thu Summer Camp2016]补退选 字典树+vector

来源:互联网 发布:豫剧板胡网络培训班 编辑:程序博客网 时间:2024/06/16 10:01

题意

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 个小写字母,强制在线

分析

一开始想到一个O(n*60*logn)的做法,是用可持久化数据结构来实现的,比较麻烦,不过貌似也能过。
其实这题可以只维护一棵字典树,每个节点记录当前以该节点为前缀时的字符串数量,开个vector记录每个长度出现的最小时间。注意只有当前数量大于vector的末尾时才将其加入,然后查找的时候二分一下就好了。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<vector>using namespace std;typedef long long LL;const int N=100005;int n,cnt;struct data{int cnt,num;};struct tree{int to[10],mx,cnt;}t[N*60];vector<data> w[N*60];char s[65];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void ins(int now,int x,int y,int num,int z){    t[now].cnt+=z;    if (t[now].cnt>t[now].mx) t[now].mx=t[now].cnt,w[now].push_back((data){t[now].cnt,num});    if (x==y) return;    if (!t[now].to[s[x]-'a']) ins(t[now].to[s[x]-'a']=++cnt,x+1,y,num,z);    else ins(t[now].to[s[x]-'a'],x+1,y,num,z);}bool cmp(data a,data b){    return a.cnt<b.cnt;}int query(int now,int x,int y,int z){    if (!now) return -1;    if (x==y)    {        vector<data>::iterator it=upper_bound(w[now].begin(),w[now].end(),(data){z,0},cmp);        if (it==w[now].end()) return -1;        else return (*it).num;    }    return query(t[now].to[s[x]-'a'],x+1,y,z);}int main(){    n=read();int lastans=0;    cnt=1;    for (int i=1;i<=n;i++)    {        int op=read();        scanf("%s",s);int len=strlen(s);        if (op==1) ins(1,0,len,i,1);        else if (op==2) ins(1,0,len,i,-1);        else        {            int a=read(),b=read(),c=read(),v=((LL)a*abs(lastans)+(LL)b)%c;            printf("%d\n",lastans=query(1,0,len,v));        }    }    return 0;}
阅读全文
0 0
原创粉丝点击