BZOJ2555【SAM】【LCT】

15 篇文章 0 订阅
6 篇文章 0 订阅

裸的SAM暴力程序跑得很快.

/* I will wait for you */

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<vector>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<string>
#define make make_pair
#define fi first
#define se second

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int maxn=2000010;
const int maxm=1010;
const int maxs=26;
const int INF=1<<29;
const int P=1000000007;
const double error=1e-9;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9') f=(ch=='-'?-1:1),ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*f;
}

struct sam
{
	sam *fa,*next[maxs];
	int len,val; 
}su[maxn],*head,*tail; 

char s[maxn],t[10];
int mas,cnt;

void init()
{
	head=tail=&su[cnt++];
}

void add(int x)
{
	sam *now=&su[cnt++],*per=tail;
	now->len=per->len+1,tail=now;
	
	for(;per&&!per->next[x];per->next[x]=now,per=per->fa);
	
	if(!per) now->fa=head;
	else if(per->len+1==per->next[x]->len) now->fa=per->next[x];
	else
	{
		sam *tmp=&su[cnt++],*pex=per->next[x];
		*tmp=*pex;tmp->len=per->len+1;
		pex->fa=now->fa=tmp;
		for(;per&&per->next[x]==pex;per->next[x]=tmp,per=per->fa);
	}
	
	for(;now!=head;now=now->fa) now->val++;
}

void insert(char* s)
{
	for(int i=0,n=strlen(s);i<n;i++) add(s[i]-'A');
}

int query(char* s)
{	
	sam *now=head;
	for(int i=0,n=strlen(s);i<n&&(now=now->next[s[i]-'A']);i++);
	return now?now->val:0;
}

void mask(char* s,int m)
{
	for(int i=0,n=strlen(s);i<n;i++) m=(m*131+i)%n,swap(s[i],s[m]);
}

int main()
{
	int n=read();init();
	scanf("%s",s),insert(s);
	
	for(int i=1,q;i<=n;i++)
	{
		scanf("%s%s",t,s),mask(s,mas);
		if(t[0]=='A') insert(s);
		if(t[0]=='Q') q=query(s),mas^=q,printf("%d\n",q);
	}
	
	return 0;
}
注意到fail指针构成了一颗树.而每次插入新节点对整体的影响是一条到根节点的链.因此可以用LCT维护.

/* I will wait for you */

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<vector>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<string>
#define make make_pair
#define fi first
#define se second

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int maxn=2000010;
const int maxm=1010;
const int maxs=26;
const int INF=1<<29;
const int P=1000000007;
const double error=1e-9;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9') f=(ch=='-'?-1:1),ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*f;
}

char s[maxn],t[10];int mas,cntn,cnts;

struct node
{
	int val,add;node *fa,*son[2];
	
	int dir() { return this==fa->son[1]; }
	int isroot() { return !fa||this!=fa->son[0]&&this!=fa->son[1]; }
}no[maxn];

node* newc(int c)
{
	node* o=&no[cntn++];
	o->val=c,o->add=0,o->fa=o->son[0]=o->son[1]=0;
	return o;
}

void pushdown(node *o)
{
	if(o->add)
	{
		for(int i=0;i<2;i++) if(o->son[i]) 
			o->son[i]->add+=o->add,o->son[i]->val+=o->add;
		o->add=0;
	}
}

void maintain(node *o)
{
	for(int i=0;i<2;i++) if(o->son[i]) o->son[i]->fa=o;
}

void rotate(node *o)
{
	node* p=o->fa;int d=o->dir();
	pushdown(p);pushdown(o);
	p->son[d]=o->son[d^1];
	o->son[d^1]=p,o->fa=p->fa;
	if(!p->isroot()) p->fa->son[p->dir()]=o;
	maintain(p),maintain(o);
}

void splay(node *o)
{
	pushdown(o);
	while(!o->isroot())
	{
		node *p=o->fa;
		if(p->isroot()) rotate(o);
		else if(o->dir()==p->dir()) rotate(p),rotate(o);
		else rotate(o),rotate(o);
	}
}

void access(node* o)
{
	for(node* t=0;o;t=o,o=o->fa) splay(o),o->son[1]=t,maintain(o);
}

void link(node* u,node* v)
{
	u->fa=v;
}

void cut(node* u)
{
	access(u),splay(u);
	if(u->son[0])
	{
		u=u->son[0];
		while(u->son[1]) u=u->son[1];
		splay(u),u->son[1]=0;
	}
}

struct sam
{
	sam *fa,*next[maxs];int len;node* c;
}su[maxn],*head,*tail; 

void init()
{
	head=&su[cnts++],head->c=newc(0),tail=head;
}

void add(int x)
{
	sam *now=&su[cnts++],*per=tail;
	now->len=per->len+1,now->c=newc(0),tail=now;
	
	for(;per&&!per->next[x];per->next[x]=now,per=per->fa);
	
	if(!per) now->fa=head,link(now->c,head->c);
	else if(per->len+1==per->next[x]->len) 
		now->fa=per->next[x],link(now->c,per->next[x]->c);
	else
	{
		sam *tmp=&su[cnts++],*pex=per->next[x];
		cut(pex->c),*tmp=*pex;
		tmp->len=per->len+1,tmp->c=newc(pex->c->val);
		link(tmp->c,tmp->fa->c);
		
		pex->fa=now->fa=tmp;
		link(pex->c,tmp->c),link(now->c,tmp->c);
		for(;per&&per->next[x]==pex;per->next[x]=tmp,per=per->fa);
	}
	
	access(now->c),splay(now->c),now->c->add++,now->c->val++;
}

void insert(char* s)
{
	for(int i=0,n=strlen(s);i<n;i++) add(s[i]-'A');
}

int query(char* s)
{	
	sam *now=head;
	for(int i=0,n=strlen(s);i<n&&(now=now->next[s[i]-'A']);i++);
	return now?(splay(now->c),now->c->val):0;
}

void mask(char* s,int m)
{
	for(int i=0,n=strlen(s);i<n;i++) m=(m*131+i)%n,swap(s[i],s[m]);
}

int main()
{
	int n=read();init();
	scanf("%s",s),insert(s);
	
	for(int i=1,q;i<=n;i++)
	{
		scanf("%s%s",t,s),mask(s,mas);
		if(t[0]=='A') insert(s);
		if(t[0]=='Q') q=query(s),mas^=q,printf("%d\n",q);
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值