【BZOJ4545】DQS的trie 后缀自动机+LCT
【BZOJ4545】DQS的trie
Description
Input
Output
Sample Input
4
1 2 a
1 3 b
2 4 b
6
1
2 2 4
2 5 b
2 6 c
5 7 b
1
3 ab
2 6 3
6 8 a
6 9 b
1
Sample Output
7
2
11
【数据范围及提示】
第一个询问,本质不同的子串是 a,b,ab。
第二个询问,本质不同的子串是 a,b,c,ab,ac,bb,abb。
第三个询问,ab出现次数是 2。
第四个询问,本质不同的子串是 a,b,c,ab,ac,ca,cb,bb,abb,aca,acb。
opt=1或3时对原树不做修改,只是询问。
每次opt=2,会增加si-1个节点,因为有一个节点是原树上作为新树的根出现的。
数据中,对于链的部分分,满足端点为根节点,每次新建子树都从尾部插入。
对于全部数据,保证从始至终每条边上的字符均为小写字母’a’或’b’或’c’。
n是最终树的大小,N<=100000,M<=100000,Si<=当前树的大小
题解:本题就是3998和2555的结合体,没做过的直接去做那两题吧。
对于第一问,我们可以动态维护所有点的mx[i]-mx[pre]之和,对于第二问,用LCT维护pre树,并将 插入一棵子树,求一个点的子树大小 变成 修改一条链上的权值,查询一个点的值 即可。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=400010;
typedef long long ll;
int n,m,tot,len,cnt;
int to[maxn],next[maxn],val[maxn],head[maxn],pos[maxn];
ll ans;
char str[maxn];
namespace LCT
{struct node{int ch[2],fa;ll tag,val;}s[maxn];int st[maxn],top;inline bool isr(int x) {return (x!=s[s[x].fa].ch[0])&&(x!=s[s[x].fa].ch[1]);}inline void pushdown(int x){if(s[x].tag){if(s[x].ch[0]) s[s[x].ch[0]].val+=s[x].tag,s[s[x].ch[0]].tag+=s[x].tag;if(s[x].ch[1]) s[s[x].ch[1]].val+=s[x].tag,s[s[x].ch[1]].tag+=s[x].tag;s[x].tag=0;}}inline void rotate(int x){int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);if(!isr(y)) s[z].ch[y==s[z].ch[1]]=x;s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1];if(s[x].ch[d^1]) s[s[x].ch[d^1]].fa=y;s[x].ch[d^1]=y;}inline void updata(int x){int y=x;st[top=1]=x;while(!isr(y)) y=s[y].fa,st[++top]=y;while(top) pushdown(st[top--]);}inline void splay(int x){updata(x);while(!isr(x)){int y=s[x].fa,z=s[y].fa;if(!isr(y)){if((x==s[y].ch[0])^(y==s[z].ch[0])) rotate(x);else rotate(y);}rotate(x);}}inline void access(int x){for(int y=0;x;splay(x),s[x].ch[1]=y,y=x,x=s[x].fa);}inline void link(int x,int y){access(x),splay(x),s[y].fa=x,s[x].val+=s[y].val,s[x].tag+=s[y].val;}inline void cut(int x){access(x),splay(x),s[s[x].ch[0]].val-=s[x].val,s[s[x].ch[0]].tag-=s[x].val;s[s[x].ch[0]].fa=0,s[x].ch[0]=0;}
}
namespace SAM
{int ch[maxn][26],pre[maxn],mx[maxn];char str[maxn];inline int extend(int p,int x){int np=++tot;mx[np]=mx[p]+1,LCT::s[np].val=1;for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=np;if(!p) pre[np]=1,ans+=mx[np],LCT::link(1,np);else{int q=ch[p][x];if(mx[q]==mx[p]+1) pre[np]=q,ans+=mx[np]-mx[q],LCT::link(q,np);else{int nq=++tot; mx[nq]=mx[p]+1;ans-=mx[q]-mx[pre[q]];LCT::cut(q);pre[nq]=pre[q],pre[np]=pre[q]=nq;ans+=mx[nq]-mx[pre[nq]]+mx[np]-mx[pre[np]]+mx[q]-mx[pre[q]];LCT::link(pre[nq],nq),LCT::link(pre[q],q),LCT::link(pre[np],np);memcpy(ch[nq],ch[q],sizeof(ch[q]));for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=nq;}}return np;}inline void query(){scanf("%s",str),len=strlen(str);int i,p=1;for(i=0;i<len&&p;i++) p=ch[p][str[i]-'a'];if(!p) puts("0");else{LCT::updata(p);printf("%lld\n",LCT::s[p].val);}}
}
inline int rd()
{int ret=0,f=1; char gc=getchar();while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();return ret*f;
}
void dfs(int x,int fa)
{for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa) pos[to[i]]=SAM::extend(pos[x],val[i]),dfs(to[i],x);head[x]=-1;
}
inline void add(int a,int b,int c)
{to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{rd(),n=rd();int i,a,b,c,d,op;tot=1,pos[1]=1;memset(head,-1,sizeof(head));for(i=1;i<n;i++) a=rd(),b=rd(),scanf("%s",str),add(a,b,str[0]-'a'),add(b,a,str[0]-'a');dfs(1,0);m=rd();for(i=1;i<=m;i++){op=rd();if(op==1) printf("%lld\n",ans);if(op==2){c=rd(),d=rd();while(--d) a=rd(),b=rd(),scanf("%s",str),add(a,b,str[0]-'a'),add(b,a,str[0]-'a');dfs(c,0);}if(op==3) SAM::query();}return 0;
}//1 4 1 2 a 1 3 b 2 4 b 6 1 2 2 4 2 5 b 2 6 c 5 7 b 1 3 ab 2 6 3 6 8 a 6 9 b 1
转载于:https://www.cnblogs.com/CQzhangyu/p/7859563.html
【BZOJ4545】DQS的trie 后缀自动机+LCT相关推荐
- BZOJ4545: DQS的trie 广义后缀自动机_LCT
特别鸣神犇 fcwww 替我调出了无数个错误(没他的话我都快自闭了),祝大佬省选rp++ 板子题,给我写了一天QAQ...... 用 LCT 维护后缀树,暴力更新用 LCT 区间更新链即可 其实,在计 ...
- 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+LCT+树状数组)
description 点击查看题目内容 solution Step1 无脑建SAMSAMSAM 两个前缀的最长公共后缀就是parent−treeparent-treeparent−tree上两点的l ...
- BZOJ.2555.SubString(后缀自动机 LCT)
题目链接 \(Description\) 给你一个字符串init,要求支持两个操作: (1)在当前字符串的后面插入一个字符串s (2)询问字符串s在当前字符串中出现了几次(作为连续子串) 强制在线. ...
- BZOJ 2555: SubString [后缀自动机 LCT]
2555: SubString Time Limit: 30 Sec Memory Limit: 512 MB Submit: 2045 Solved: 583 [Submit][Status][ ...
- 【BZOJ4545】DQS的trie
Description DQS的自家阳台上种着一棵颗粒饱满.颜色纯正的trie. DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符.并且,它拥有极强的生长力:某个i时刻 ...
- 【bzoj3926】[Zjoi20150]诸神眷顾的幻想乡 后缀自动机+trie
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- 从零开始の后缀自动机
后缀自动机,一个处理字符串问题的神器.听起来很神圣,貌似很难写.其实代码实现并不复杂,萌新估计都能学会. 以前听学长们讲过好多次也看过陈立杰的课件,都不是很明白.今天终于弄明白了,就写一个让大家都能看 ...
- 【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机
[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝 ...
- BZOJ3277 串 【广义后缀自动机】
Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...
最新文章
- Windows Java、Tomcat、MySQL安装过程
- 36岁 计算机博士,36岁考博士
- Spring Boot 之spring.factories
- python slice函数怎么取列表的最后一个数_python slice函数_python中slice函数如何实现?...
- 操作系统学习---虚拟内存
- 高仿富途牛牛-组件化(五)-如何去管理炒鸡多的小窗口
- @程序员,如何解决开发和运维之间的固有隔阂?
- pytorch实现猫狗分类+数据集
- android多个声音输出,Android新增一个音频类型及双音频输出的实现
- 免费在线汉信码识别(Online Hanxin Decoder)
- 视频分割算法在移动端如何应用
- ASP.NET MVC里ModelState.IsValid总是true或者总是false
- 2.8.5Django --3 WEB框架
- 日志收集Agent,阴暗潮湿的地底世界
- js 倒计时算法及定时器的应用
- 央视《家有妙招》整理版,共125招,值得永远收藏
- 课件(Part 1, PJ)
- 图片文字怎么转换成文本?可以试试这三种途径
- GBN,SR,TCP协议实现可靠数据传输的原理
- 使用U盘安装windows系统教程