bzoj2555


Description

  
    懶得寫背景了,給你一個字符串init,要求你支持兩個操作
    
    (1):在當前字符串的後面插入一個字符串
    
    (2):詢問字符串s在當前字符串中出現了幾次?(作爲連續子串)
    
    你必須在線支持這些操作。
    

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





這題題目的加密過程好像沒有描述清楚。。。
大概是這樣的:
mask1 = mask
加密
mask = mask1


很有意思的一道題。
構造後綴自動機,然後每個串放進去匹配,如果匹配長度達到匹配串長度了那麼就當前點的right集合就是答案。
right集合怎麼求呢,我們把每個點(除了根節點)向它的pre連邊,這樣就構成了一棵樹,然後對於後綴自動機上沒有新建的點,right[x]=1,然後在這棵樹上,right[x] += sigma(right[son[i]])
那麼我們很顯然可以寫出暴力,對於新加進來的節點,可能會在這棵樹上加一條邊,或者在樹上刪除一條邊,設加入(x,pre[x])這條邊,那麼我們就把pre[x]->根的路徑上都加上right[x],刪除的話就減去。
這樣直接做的話最壞情況是n*n級別的但是一般情況下是跑得很快。
考慮這棵樹是變化的,然後這裏的操作就是路徑加上一個值,路徑減去一個值,這樣可以用動態樹維護,但是實際上這樣做速度是非常慢的但是複雜度靠譜!!!!
附上代碼
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 600005;
int sum[MAXN << 1], fa[MAXN << 1], lc[MAXN << 1], rc[MAXN << 1], cnt[MAXN << 1];
int ch[MAXN << 1][26], pre[MAXN << 1], dis[MAXN << 1], num[MAXN << 1];
int n, i, j, k, l, m, t = 1, p = 1, q, tag[MAXN << 1], len, tot;
char s[MAXN], c[10];
inline bool isroot(int x)
{
	return (lc[fa[x]] == x || rc[fa[x]] == x);
}
inline void rev(int x)
{
	swap(lc[x], rc[x]);
	cnt[x] ^= 1;
}
inline void putdown(int x)
{
	if (cnt[x])
	{
		cnt[x] = 0;
		if (lc[x]) rev(lc[x]);
		if (rc[x]) rev(rc[x]);
	}
	if (num[x])
	{
		if (lc[x]) num[lc[x]] += num[x], sum[lc[x]] += num[x];
		if (rc[x]) num[rc[x]] += num[x], sum[rc[x]] += num[x];
		num[x] = 0;
	}
}
inline void turn(int x)
{
	int y = fa[x], z = fa[y], b = 0;
	if (lc[y] == x) b = rc[x];
	else b = lc[x];
	if (b) fa[b] = y;
	fa[x] = z; fa[y] = x;
	if (z)
		if (lc[z] == y) lc[z] = x;
		else if (rc[z] == y) rc[z] = x;
	if (lc[y] == x) rc[x] = y, lc[y] = b;
	else lc[x] = y, rc[y] = b;
}
inline void splay(int x)
{
	int i;
	for(i = x; isroot(i); i = fa[i])
		tag[++len] = i;
	tag[++len] = i;
	while (len) putdown(tag[len --]);
	while (isroot(x))
	{
		if (isroot(fa[x]))
			if ((lc[fa[x]] == x) == (lc[fa[fa[x]]] == fa[x])) turn(fa[x]);
			else turn(x);
		turn(x);
	}
}
inline void access(int x)
{
	int sb = 0;
	while (x)
	{
		splay(x);
		rc[x] = sb;
		sb = x;
		x = fa[x];
	}
}
inline void makeroot(int x)
{
	access(x);
	splay(x);
	rev(x);
}
inline void split(int x, int y, int w)
{
	makeroot(x);
	access(y);
	splay(y);
	num[y] += w;
	sum[y] += w;
}
inline void Link(int x, int y)
{
	makeroot(x);
	fa[x] = y;
	if (sum[x]) split(y, 1, sum[x]);
}
inline void Cut(int x, int y)
{
	makeroot(x);
	access(y);
	splay(y);
	lc[y] = fa[x] = 0;
	if (sum[x]) split(y, 1, -sum[x]);
}
inline void add(int x)
{
	int np = ++t;
	sum[np] = 1;
	dis[np] = dis[p] + 1;
	for(; p && !ch[p][x]; p = pre[p])
		ch[p][x] = np;
	if (!p) pre[np] = 1, Link(np, 1);
	else {
		int q = ch[p][x];
		if (dis[q] == dis[p] + 1) pre[np] = q, Link(np, q);
		else {
			int nq = ++t;
			dis[nq] = 1 + dis[p];
			for(int i = 0; i < 26; i ++)
				ch[nq][i] = ch[q][i];
			pre[nq] = pre[q];
			Link(nq, pre[nq]);
			Cut(q, pre[q]);
			pre[np] = pre[q] = nq;
			Link(np, nq);
			Link(q, nq);
			for(; p && ch[p][x] == q; p = pre[p])
				ch[p][x] = nq;
		}
	}
	p = np;
}
int main()
{
	cin >> q;
	scanf("%s", s + 1);
	n = strlen(s + 1);
	for(i = 1; i <= n; i ++)
		add(s[i] - 'A');
	while (q --)
	{
		scanf("%s", c);
		scanf("%s", s);
		n = strlen(s);
		int tot1 = tot;
		for(i = 0; i < n; i ++)
		{
			tot = (tot * 131 + i) % n;
			swap(s[i], s[tot]);
		}
		tot = tot1;
		if (c[0] == 'A')
		{
			for(i = 0; i < n; i ++)
				add(s[i] - 'A');
		}
		else
		{
			int pyz = 0, now = 1, fp = 0;
			for(i = 0; i < n; i ++)
			{
				int x = s[i] - 'A';
				if (ch[now][x]) now = ch[now][x], pyz ++;
				else {
					for(; now && !ch[now][x]; now = pre[now]);
					if (!now) now = 1, pyz = 0;
					else pyz = dis[now] + 1, now = ch[now][x];
				}
				if (pyz == n) {splay(now); printf("%d\n", sum[now]); tot ^= sum[now]; fp = 1; break;}
			}
			if (!fp) {printf("0\n"); tot ^= 0;}
		}
	}
}

發佈了44 篇原創文章 · 獲贊 11 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章