BZOJ2555 SubString【SAM + Link Cut Tree】
BZOJ2555. SubString
要求在线询问一个串在原串中出现的次数,并且可以在原串末尾添加字符串
如果没有修改的话,考虑建出\(parent\)树之后统计每个\(endpos\)节点的\(right\)集合大小,现在要求动态添加字符,那么由于\(parent\)树的形态会变,所以用\(LCT\)来维护\(parent\)树,具体就是增删\(link\)边
\(LCT\)一直以初始状态为根,每次提出来初始状态到当前节点的链然后更新一条链上的值即可,根一直没变,不需要\(makeroot\)操作也不需要\(split\)操作,直接\(access\)当前点,然后\(splay\)上去之后更新
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN = (6e5+7)*2;
void decode(string& str, int mask){
    for(int i = 0; i < (int)str.size(); i++){
        mask = (mask*131+i)%str.size();
        swap(str[i],str[mask]);
    }
}
struct LinkCutTree{
    int ch[MAXN][2],fa[MAXN],val[MAXN],lazy[MAXN],rev[MAXN];
    bool isroot(int rt){ return ch[fa[rt]][0]!=rt and ch[fa[rt]][1]!=rt; }
    int check(int rt){ return rt == ch[fa[rt]][1]; }
    void pushdown(int rt){
        if(rev[rt]){
            swap(ch[rt][0],ch[rt][1]);
            rev[ch[rt][0]] ^= 1;
            rev[ch[rt][1]] ^= 1;
            rev[rt] ^= 1;
        }
        if(lazy[rt]){
            if(ch[rt][0]){
                val[ch[rt][0]] += lazy[rt];
                lazy[ch[rt][0]] += lazy[rt];
            }
            if(ch[rt][1]){
                val[ch[rt][1]] += lazy[rt];
                lazy[ch[rt][1]] += lazy[rt];
            }
            lazy[rt] = 0;
        }
    }
    void pushdownall(int rt){
        if(!isroot(rt)) pushdownall(fa[rt]);
        pushdown(rt);
    }
    void rotate(int rt){
        int f = fa[rt], gf = fa[f], d = check(rt);
        if(!isroot(f)) ch[gf][check(f)] = rt;
        fa[rt] = gf;
        ch[f][d] = ch[rt][d^1]; fa[ch[rt][d^1]] = f;
        ch[rt][d^1] = f; fa[f] = rt;
    }
    void splay(int rt){
        pushdownall(rt);
        while(!isroot(rt)){
            int f = fa[rt];
            if(!isroot(f)){
                if(check(rt)==check(f)) rotate(f);
                else rotate(rt);
            }
            rotate(rt);
        }
    }
    void access(int rt){
        int c = 0;
        while(rt){
            splay(rt);
            ch[rt][1] = c;
            rt = fa[c = rt];
        }
    }
    void link(int x, int f){
        fa[x] = f; access(f); splay(f);
        val[f] += val[x]; lazy[f] += val[x];
    }
    void cut(int u){
        access(u);
        splay(u);
        lazy[ch[u][0]] -= val[u];
        val[ch[u][0]] -= val[u];
        fa[ch[u][0]] = 0; ch[u][0] = 0;
    }
    int query(int u){
        splay(u);
        return val[u];
    }
}lct;
struct SAM{
    int len[MAXN],link[MAXN],ch[MAXN][26],tot,last;
    SAM(){ link[last = tot = 1] = 0; }
    void extend(int c){
        int np = ++tot, p = last;
        lct.val[np] = 1;
        len[np] = len[last] + 1;
        while(p and !ch[p][c]){
            ch[p][c] = np;
            p = link[p];
        }
        if(!p){
            link[np] = 1;
            lct.link(np,1);
        }
        else{
            int q = ch[p][c];
            if(len[p]+1==len[q]){
                link[np] = q;
                lct.link(np,q);
            }
            else{
                int clone = ++tot;
                len[clone] = len[p] + 1;
                link[clone] = link[q];
                lct.link(clone,link[q]);
                for(int i = 0; i < 26; i++) ch[clone][i] = ch[q][i];
                lct.cut(q); lct.link(q,clone);
                lct.link(np,clone);
                link[np] = link[q] = clone;
                while(p and ch[p][c]==q){
                    ch[p][c] = clone;
                    p = link[p];
                }
            }
        }
        last = np;
    }
    int calsub(string s){
        int u = 1;
        for(int i = 0; i < (int)s.size(); i++){
            int c = s[i] - 'A';
            if(!ch[u][c]) return 0;
            u = ch[u][c];
        }
        return lct.query(u);
    }
}sam;
int n,mask;
string s,op;
int main(){
    //ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> s;
    for(int i = 0; i < (int)s.size(); i++) sam.extend(s[i]-'A');
    while(n--){
        cin >> op >> s;
        decode(s,mask);
        if(op[0]=='Q'){
            int ret = sam.calsub(s);
            mask ^= ret;
            cout << ret << endl;
        }
        else for(int i = 0; i < (int)s.size(); i++) sam.extend(s[i]-'A');
    }
    return 0;
}
BZOJ2555 SubString【SAM + Link Cut Tree】的更多相关文章
- [BZOJ 1036] [ZJOI2008] 树的统计Count 【Link Cut Tree】
		题目链接:BZOJ - 1036 题目分析 这道题可以用树链剖分,块状树等多种方法解决,也可以使用 LCT. 修改某个点的值时,先将它 Splay 到它所在的 Splay 的根,然后修改它的值,再将它 ... 
- CF614A 【Link/Cut Tree】
		题意:求出所有w^i使得l<=w^i<=r 输入为一行,有三个数,分别是l,r,w.意义如题目所描述 输出为一行,输出所有满足条件的数字,每两个数字中间有一个空格 如果没有满足条件的数字则 ... 
- P3690 【模板】Link Cut Tree (动态树)
		P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ... 
- LG3690 【模板】Link Cut Tree (动态树)
		题意 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的 ... 
- AC日记——【模板】Link Cut Tree 洛谷 P3690
		[模板]Link Cut Tree 思路: LCT模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 30 ... 
- LG3690 【模板】Link Cut Tree 和 SDOI2008 洞穴勘测
		UPD:更新了写法. [模板]Link Cut Tree 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 后接两个整数(x,y),代表询问从x到y ... 
- (RE) luogu P3690 【模板】Link Cut Tree
		二次联通门 : luogu P3690 [模板]Link Cut Tree 莫名RE第8个点....如果有dalao帮忙查错的话万分感激 #include <cstdio> #includ ... 
- LuoguP3690 【模板】Link Cut Tree (动态树)  LCT模板
		P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ... 
- 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)
		题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ... 
随机推荐
- HBase 底层原理详解(深度好文,建议收藏)
			HBase简介 HBase 是一个分布式的.面向列的开源数据库.建立在 HDFS 之上.Hbase的名字的来源是 Hadoop database,即 Hadoop 数据库.HBase 的计算和存储能力 ... 
- 想学Python不知如何入门,教你!
			一.入门引导 想必有很多小伙伴想学习Python,又不知道如何入门,总觉得学习一定要头悬梁,锥刺股!NO,今天给大家分享下如何轻松入门Python! 首先,我们要学习Python,那一定要和你 ... 
- 剑指offer  面试题10.2:青蛙变态跳台阶
			题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级--它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 编程思想 因为n级台阶,第一步有n种跳法:跳1级.跳2级.到跳n级跳1级,剩下 ... 
- 【RAC】双节点RAC搭建
			本文主要是双节点的RAC进行搭建,根据黄伟老师的视频进行总结和使用. 搭建环境: 1.两台安装好Linux_x64系统的服务器 2.IP设置 注意:Priv-IP的IP是自己一个网段,而剩下的SCAN ... 
- ORA-00054: 資源正被使用中, 請設定 NOWAIT 來取得它, 否則逾時到期
			1.查看被使用资源的OBJECT_ID SELECT *FROM DBA_OBJECTS WHERE OBJECT_NAME='OBJECT_NAME' 2.查看资源被谁占用SELECT * FROM ... 
- 通过电脑浏览器调试真机h5兼容问题
			前言 在h5开发过程中,起初我们使用PC浏览器的手机模式打开开发中的页面,并使用控制台进行调试,但实际真机兼容性问题无法调试到:在这种情况下,我们通常使用vConsole(即移动端的控制台)来调试,但 ... 
- argparse的简单使用
			简单记录一下argparse的用法 这个是针对我做区块链的一些demo时需要用到的,仅把用到了的一些操作记录,argparse很强大,更多细致的操作可以参考:https://docs.python.o ... 
- node集群(cluster)
			使用例子 为了让node应用能够在多核服务器中提高性能,node提供cluster API,用于创建多个工作进程,然后由这些工作进程并行处理请求. // master.js const cluster ... 
- Linux下unix socket 读写 抓包
			Linux下unix socket 读写 抓包-ubuntuer-ChinaUnix博客 http://blog.chinaunix.net/uid-9950859-id-247877.html 
- 签名  sign key 纸质邮件 历史 RSA诞生历史
			API接口签名校验,如何安全保存appsecret? - 知乎 https://www.zhihu.com/question/40855191 要保证一般的客户端-服务器通信安全,可以使用3个密钥. ... 
