BZOJ2555 SubString

@(XSY)[LCT]

Description

懒得写背景了,给你一个字符串init,要求你支持两个操作

  1. 在当前字符串的后面插入一个字符串
  2. 询问字符串s在当前字符串中出现了几次?(作为连续子串)
  3. 你必须在线支持这些操作。

Input

第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压

Output

对于每个询问的答案.

Sample Input

2
A
QUERY B
ADD BBABBBBAAB

Sample Output

0

HINT

40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20

Solution

这题的思路还是非常显而易见的.
由于要求在线处理, 我们对字符串用后缀自动机处理, 建立出parent tree.
根据parent tree的性质, 一个父亲节点所表示的所有substrings的出现位置相同, 并且为其所有子节点的substrings的出现位置的集合的并. 所以我们可以用link-cut-tree维护这一棵parent tree. 在插入一个字符时, 对其所对应的parent tree上到根的路径上的节点全部加一. 查询时直接输出一个点上的值即可.
link-cut-tree太久没有写过了, 非常不熟练. 代码中标注了一些写的时候容易出错的地方.

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

const int LEN = 1 << 20, ORG = 'A', LIM = 1 << 5;

namespace Zeonfai
{
	inline int getInt()
	{
		int a = 0, sgn = 1;
		char c;
		
		while(! isdigit(c = getchar()))
			if(c == '-')
				sgn *= -1;
		
		while(isdigit(c))
			a = a * 10 + c - '0', c = getchar();
		
		return a * sgn;
	}
	
	inline int getString(char *str)
	{
		char c;
		
		while(! isgraph(c = getchar()));
		
		int len = 0;
		
		while(isgraph(c))
			str[len ++] = c, c = getchar();
		
		return len;
	}
}

struct linkCutTree
{
	struct node
	{
		node *pre, *suc[2];
		int w, tag, isRoot;

		inline node()
		{
			pre = suc[0] = suc[1] = NULL;
			w = tag = 0;
			isRoot = 1;
		}
		
		inline void add(int a)
		{
			if(this == NULL)
				return;
			
			tag += a, w += a;
		}
		
		inline void pushdown()
		{
			if(! isRoot)
				pre->pushdown();
			
			suc[0]->add(tag), suc[1]->add(tag);
			tag = 0;
		}
		
		inline int getRelation()
		{
			if(pre == NULL)
				return -1;
			
			return this == pre->suc[1];
		}
	};
	
	inline void rotate(node *u)
	{
		node *pre = u->pre, *prepre = pre->pre;
		int k = u->getRelation();
		
		if(u->suc[k ^ 1] != NULL)
			u->suc[k ^ 1]->pre = pre;
		
		pre->suc[k] = u->suc[k ^ 1];
		u->suc[k ^ 1] = pre;	
		u->pre = prepre;
		
		if(! pre->isRoot) //Link-cut-tree的Splay不要写错 
			prepre->suc[pre->getRelation()] = u;
		else
			u->isRoot = 1, pre->isRoot = 0;
			
		pre->pre = u;
	}
	
	inline void splay(node *u)
	{
		u->pushdown();
		
		while(! u->isRoot)
		{
			if(! u->pre->isRoot)
				rotate(u->getRelation() == u->pre->getRelation() ? u->pre : u);
		
			rotate(u);
		}
	}
	
	inline void access(node *u)
	{
		splay(u);
		
		while(u->pre != NULL)
		{
			node *pre = u->pre;
			splay(pre);
			
			if(pre->suc[1] != NULL)
				pre->suc[1]->isRoot = 1;
			
			u->isRoot = 0;
			pre->suc[1] = u;
			splay(u);
		}
	}
	
	inline void cut(node *u)
	{
		access(u);
		
		if(u->suc[0] != NULL)
			u->suc[0]->pre = NULL, u->suc[0]->isRoot = 1;
		
		u->suc[0] = NULL;
	}
	
	inline void link(node *u, node *pre)
	{
		cut(u);
		u->pre = pre;
	}
}tr;

struct suffixAutomaton
{
	struct state
	{
		int stp;
		linkCutTree::node *treeNode;
		state *pre, *suc[LIM];

		inline state(int _stp = 0)
		{
			stp = _stp;
			treeNode = new linkCutTree::node;
			pre = NULL;
			memset(suc, NULL, sizeof(suc));
		}
	};

	state *s, *lst;
	
	inline void init()
	{
		s = lst = new state(); //初始化时新建源点 
	}

	inline void add(int c)
	{
		state *p = lst, *u = new state(p->stp + 1);

		for(; p != NULL && p->suc[c] == NULL; p = p->pre)
			p->suc[c] = u;

		if(p == NULL)
			u->pre = s, tr.link(u->treeNode, s->treeNode);
		else
		{
			state *q = p->suc[c];

			if(q->stp == p->stp + 1)
				u->pre = q, tr.link(u->treeNode, q->treeNode);
			else
			{
				state *v = new state(p->stp + 1);
				v->pre = q->pre;
				memcpy(v->suc, q->suc, sizeof(q->suc));
				tr.link(v->treeNode, q->pre->treeNode);
				q->pre = u->pre = v;
				tr.link(q->treeNode, v->treeNode), tr.link(u->treeNode, v->treeNode);
				v->treeNode->w = q->treeNode->w;
				
				for(; p != NULL && p->suc[c] == q; p = p->pre)
					p->suc[c] = v;
			}
		}

		lst = u;
		tr.access(u->treeNode);
		u->treeNode->add(1);
	}

	inline void insert(char *str, int len)
	{
		for(int i = 0; i < len; ++ i) //插入时不需要新建源点 
			add(str[i] - ORG);
	}
	
	inline int query(char *str, int len)
	{
		state *p = s;
		int i;
		
		for(i = 0; p != NULL && i < len; ++ i)
			p = p->suc[str[i] - 'A'];
		
		if(p != NULL)
		{
			p->treeNode->pushdown();
			return p->treeNode->w;
		}
		
		return 0;
	}
}org;

inline void decodeWithMask(char *str, int len, int mask)
{
	for(int i = 0; i < len; ++ i)
	{
		mask = (mask * 131 + i) % len;
		std::swap(str[i], str[mask]);
	}
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("bzoj2555.in", "r", stdin);
	freopen("bzoj2555.out", "w", stdout);
	#endif
	
	using namespace Zeonfai;

	int q = getInt();
	static char str[LEN];
	int len = getString(str);
	org.init();
	org.insert(str, len);
	int mask = 0;
	
	while(q --)
	{
		char opt[1 << 4];
		getString(opt);
		int len = getString(str);
		decodeWithMask(str, len, mask);
		
		if(opt[0] == 'A')
			org.insert(str, len);
		else
		{
			int ans = org.query(str, len);
			mask ^= ans;
			printf("%d\n", ans);
		}
	}
}

posted @ 2017-03-27 15:33  Zeonfai  阅读(154)  评论(0编辑  收藏  举报