zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    		}
    	}
    }
    
    
  • 相关阅读:
    (二) 线程创建、中止、中断、线程Join、优先级、调度
    cmake 生成64位项目
    ffmpeg + sdl player console
    ffmpeg cmd
    ffmpeg coco2d-x lua test
    ffmpeg windows config win32/win64 compile
    ffmpeg configure --help
    ffmpeg Windows platfrom ndk compile ffmpeg
    NDK r21编译FFmpeg 4.2.2(x86、x86_64、armv7、armv8)
    解决NDK交叉编译 selected processor does not support ARM mode libtheora的错误
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6627009.html
Copyright © 2011-2022 走看看