题目概述
有n个事件,分为三类:
1.插入字符串S。
2.删除字符串S。
3.求最小的pos,使第pos个事件结束后,以S为前缀的字符串个数>v。
解题报告
这种插入和删除字符串还要问前缀(而且还有强制在线)的题目我们不难想到用Trie解决。只是这个询问比较奇怪,但用STL乱搞就很容易了(滑稽:P)。
为每一个Trie节点记录一个vector,表示w分别为1,2,3,…时的最早事件编号,那么每次询问v时输出w为v+1时的最早事件编号就行了(因为每次w只会+1,所以v+1的最早事件编号绝对比>v+1的最早事件编号小),非常暴力……
但是这样vector会不会炸空间呢?不会。思考一下我们会发现只有插入的时候vector才会进入新的元素,删除是不会的(因为删除让w减小了)。而每次插入最多遍历到len(len是字符串长度)个节点,所以所有节点vector元素的总数为n*len,是可以承受的。
ps:这道题题目描述自相矛盾,没有说清楚到底是26个小写字母还是10个小写字母,不过好像用指针动态处理就没什么事了(但我还是开了10=_=)
示例程序
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=100000,maxl=60,maxt=maxn*maxl,maxi=10;
int te,ans;
char s[maxl+5];
struct Trie
{
struct node
{
int w,id;node* son[maxi];vector<int> que;
node(int a,int b) {w=a;id=b;for (int i=0;i<maxi;i++) son[i]=0;}
};
typedef node* P_node;
int si;P_node ro;
Trie() {si=0;ro=new node(0,0);}
int ID(char ch) {return ch-'a';}
void Insert(char *s,int te)
{
P_node pos=ro;
for (int i=1;s[i];i++)
{
if (!pos->son[ID(s[i])]) pos->son[ID(s[i])]=new node(0,++si);
pos=pos->son[ID(s[i])];pos->w++;
int num=pos->que.size();
if (!num||pos->w>num) pos->que.push_back(te);
//新的w出现了,把事件编号加入vector
}
}
void Delete(char *s)
{
P_node pos=ro;
for (int i=1;s[i];i++) pos=pos->son[ID(s[i])],pos->w--;
}
int Find(char *s,int v)
{
P_node pos=ro;
for (int i=1;s[i];i++)
if (!pos->son[ID(s[i])]) return -1; else
pos=pos->son[ID(s[i])];
int num=pos->que.size();
if (num<=v) return -1;
return pos->que[v]; //输出v+1的最小事件编号
}
};
Trie tr;
char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
int reads(char *s)
{
int len=0;char ch=readc();if (ch==EOF) return EOF;
s[++len]=ch;while ('a'<=s[len]&&s[len]<='z') s[++len]=readc();
s[len--]=0;return len;
}
int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst=ch;
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
x=tot*f;
return Eoln(ch);
}
int absi(int x) {if (x<0) return -x; else return x;}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(te);
for (int i=1;i<=te;i++)
{
int td;readi(td);reads(s);
if (td==1) tr.Insert(s,i); else
if (td==2) tr.Delete(s); else
{
int a,b,c;readi(a);readi(b);readi(c);
printf("%d\n",ans=tr.Find(s,((LL)a*absi(ans)+b)%c));
}
}
return 0;
}