zoukankan      html  css  js  c++  java
  • Luogu P5212 【SubString】

    Description

    传送门


    Solution

    动态加入字符就用(SAM),发现答案就是一个点的子树的(siz)之和,所以需要动态维护子树和,上(LCT)

    (lCT)上每个节点,(siz)表示(Splay)上大小,(lsiz)表示虚子树大小,修改(Update)(Access)(Link)函数进行修改即可。

    最后答案就是(Splay)上深度比它大的节点的(siz)之和加上它的虚子树大小,如果它是字符串的前缀,再加一。


    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int N = 1200050;
    const int INF = 999999999;
    
    int fa[N], son[N][26], last = 1, cnt = 1, len[N], rev[N], n, mask, ans;
    
    char s[3000050];
    
    struct LCT
    {
    	int son[2], siz, lsiz, fa, v;
    } tr[N + 50];
    
    bool Is(int x)
    {
    	return tr[tr[x].fa].son[1] != x && tr[tr[x].fa].son[0] != x;
    }
    
    int Get(int x)
    {
    	return tr[tr[x].fa].son[1] == x;
    }
    
    void Rv(int x)
    {
    	rev[x] ^= 1;
    	swap(tr[x].son[0], tr[x].son[1]);
    	return;
    }
    
    void Pushdown(int x)
    {
    	if (rev[x])
    	{
    		if (tr[x].son[0]) Rv(tr[x].son[0]);
    		if (tr[x].son[1]) Rv(tr[x].son[1]);
    		rev[x] = 0;
    		return;
    	}
    }
    void Update(int x)
    {
    	tr[x].siz = tr[tr[x].son[0]].siz + tr[tr[x].son[1]].siz + tr[x].lsiz + tr[x].v;
    	return;
    }
    
    void Rotate(int x)
    {
    	int f = tr[x].fa, p = tr[f].fa, d = Get(x);
    	if (!Is(f)) tr[p].son[Get(f)] = x;
    	tr[x].fa = p;
    	tr[f].son[d] = tr[x].son[d ^ 1];
    	if (tr[f].son[d]) tr[tr[f].son[d]].fa = f;
    	tr[x].son[d ^ 1] = f;
    	tr[f].fa = x;
    	Update(f); 
    	Update(x);
    	return;
    }//旋转,记得判断父亲是不是splay的根 
    
    void Calc(int x)
    {
    	if (!Is(x)) Calc(tr[x].fa);
    	Pushdown(x);
    	return;
    }//递归处理标记 
    
    void Splay(int x)
    {
    	Calc(x);
    	while (!Is(x))
    	{
    		int f = tr[x].fa;
    		if (!Is(f))
    			Get(f) ^ Get(x) ? Rotate(x) : Rotate(f);
    		Rotate(x);
    	}
    	return;
    }
    
    void Access(int x)
    {
    	int p = 0;
    	while (x)
    	{
    		Splay(x);
    		tr[x].lsiz += tr[tr[x].son[1]].siz - tr[p].siz;
    		tr[x].son[1] = p;
    		Update(x);
    		p = x;
    		x = tr[x].fa;
    	}
    	return;
    }
    
    void Makeroot(int x)
    {
    	Access(x);
    	Splay(x);
    	Rv(x); 
    	return;
    }
    
    int Findroot(int x)
    {
    	Access(x);
    	Splay(x);
    	while (tr[x].son[0]) Pushdown(x), x = tr[x].son[0];
    	Splay(x);
    	return x;
    }
    
    void Link(int u, int v)
    {
    	Makeroot(u);
    	if (Findroot(v) == u) return;
    	tr[u].fa = v; tr[v].lsiz += tr[u].siz;
    	Update(v);
    	return;
    }
    
    void Cut(int u, int v)
    {
    	Makeroot(u);
    	if (Findroot(v) != u || tr[v].fa != u || tr[v].son[0]) return;
    	tr[u].son[1] = tr[v].fa = 0;
    	Update(u);
    	return;
    }
    
    int Askk(int x)
    {
    	Makeroot(1); Access(x); Splay(x);
    	return tr[x].lsiz + tr[x].v + tr[tr[x].son[1]].siz;
    }
    
    void Init(int x)
    {
    	tr[x].siz = tr[x].v = 1;
    	return;
    }
    
    void Change(int x, int y)
    {
    	if (fa[x]) Cut(x, fa[x]);
    	Link(x, fa[x] = y);
    	return;
    }
    
    void Insert(int c)
    {
    	int p = last, ne = last = ++cnt;
    	len[ne] = len[p] + 1; Init(ne);
    	while (p && !son[p][c]) son[p][c] = ne, p = fa[p];
    	if (!p) { Change(ne, 1); return; }
    	int q = son[p][c];
    	if (len[q] == len[p] + 1) { Change(ne, q); return; }
    	int sp = ++cnt;
    	for (int i = 0; i < 26; i++) son[sp][i] = son[q][i];
    	len[sp] = len[p] + 1;
    	Change(sp, fa[q]);
    	Change(q, sp); Change(ne, sp);
    	while (p && son[p][c] == q) son[p][c] = sp, p = fa[p];
    	return;
    }
    
    void Work()
    {
    	scanf("%s", s); n = strlen(s);
    //	return;
    	int rec = mask;
    	for (int i = 0; i < n; i++)
    	{
    		rec = (rec * 131 + i) % n;
    		swap(s[rec], s[i]);
    	}
    	return;
    }
    
    void Ask()
    {
    	int now = 1, ans = 0;
    	Work();
    	for (int i = 0; i < n && now; i++) now = son[now][s[i] - 'A'];
    	if (!now) puts("0");
    	else printf("%d
    ", ans = Askk(now));
    	mask ^= ans;
    	return;
    }
    
    void Add()
    {
    	Work();
    	for (int i = 0; i < n; i++) Insert(s[i] - 'A');
    	return;
    }
    
    int main()
    {
    	int t;
    	char st[10];
    	scanf("%d", &t);
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	for (int i = 1; i <= n; i++) Insert(s[i] - 'A');
    	while (t--)
    	{
    		scanf("%s", st + 1);
    		if (st[1] == 'Q') Ask();
    		else Add();
    	}
    	return 0;
    }
    
  • 相关阅读:
    依赖注入
    Java实现一个字符串的反转
    LRU缓存介绍与实现 (Java)
    Java中HashMap遍历的两种方法(转)
    java中判断字符串是否为只包含数字
    LeakCanary 的使用遇到的弯路
    转: BAT等研发团队的技术博客
    转: android 内存检测工具 LeakCanary 说明
    转:安桌开发开源库的推荐1
    转: 技术牛人博客
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13138933.html
Copyright © 2011-2022 走看看