把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5335】[THUSC2016] 补退选(指针实现Trie)

点此看题面

大致题意: 三种操作:加入一个字符串,删除一个字符串,求最早什么时候以某个字符串为前缀的字符串个数超过给定值。

\(Trie\)

这道题显然是\(Trie\)的暴力裸题。

考虑我们对于\(Trie\)上的每个节点,开一个\(vector\),其中第\(i\)位(注意\(vector\)的下标是从\(0\)开始的)存储以这个节点所代表的字符串为前缀的字符串个数超过\(i\)的最早时间。

至于这怎么维护,只要同时再维护一下对于每个字符串当前以其为前缀的字符串个数,由于这个个数每次最多修改\(1\),因此我们只要在每次修改时比较个数与\(vector\)\(size\),若个数超过了\(vector\)\(size\),就在\(vector\)\(push\_back\)当前时间。

询问时只要找到对应节点,如果\(vector\)\(size\)大于询问的给定值\(v\),就返回\(vector\)的第\(v\)位,否则返回\(-1\)

关于内存

一开始,我很自信的把数组开到了\(10^5*60\),又由于没看见题目中说只有前十个小写字母,所以就完美地\(MLE\)了......

然后想了想发现\(Trie\)的数组是显然用不满的,但究竟该开多大呢?

思索半天没有结果,一狠心便去学了发指针实现\(Trie\),然后写完调了调\(bug\),就过了此题。

看看此时内存,仅有\(40.58MB\),真是无语......

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define K 60
using namespace std;
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
		I void reads(string& x) {x="";W(isspace(c=tc()));W(x+=c,!isspace(c=tc())&&~c);}
		Tp I void write(Ty x) {x<0&&(pc('-'),x=-x);W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
		Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class Trie//指针实现Trie
{
	private:
		struct node
		{
			int V;node *S[10];vector<int> P;
			I node() {V=0,P.clear();for(RI i=0;i^10;++i) S[i]=NULL;}//初始化清空节点,一定要写,不然会挂
		}*rt;
	public:
		I Trie() {rt=new node;}//初始化根节点
		I void Upt(Con string& s,CI v,CI ti)//修改(插入/删除)
		{
			node *x=rt;for(RI i=0,l=s.length(),t;i^l;++i)
				x->S[t=s[i]-97]==NULL&&(x->S[t]=new node),x=x->S[t],//如果子节点为空,新建子节点
				(x->V+=v)>x->P.size()&&(x->P.push_back(ti),0);//更新vector
		}
		I int Qry(Con string& s,CI v)//询问
		{
			node *x=rt;for(RI i=0,l=s.length(),t;i^l;++i)
				if(x->S[t=s[i]-97]==NULL) return -1;else x=x->S[t];//如果子节点为空,直接返回-1
			return x->P.size()>v?x->P[v]:-1;//判断是否有解,有解则返回答案,否则返回-1
		}
}T;
int main()
{
	RI Qt,i,op,x,y,z,lst=0;string s;for(F.read(Qt),i=1;i<=Qt;++i) switch(F.read(op),op)
	{
		case 1:F.reads(s),T.Upt(s,1,i);break;
		case 2:F.reads(s),T.Upt(s,-1,i);break;
		case 3:F.reads(s),F.read(x,y,z),F.writeln(lst=T.Qry(s,(1LL*x*abs(lst)+y)%z));break;//注意1LL,我原本没写就挂成了60分
	}return F.clear(),0;
}
posted @ 2019-12-22 09:53  TheLostWeak  阅读(167)  评论(0编辑  收藏  举报