【BZOJ4545】DQS的trie

Description

DQS的自家阳台上种着一棵颗粒饱满、颜色纯正的trie。
DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符。并且,它拥有极强的生长力:某个i时刻,某个节点就会新生长出一颗子树,它拥有si个节点且节点之间的边上有一个字符,并且新生长出来的子树也是一个树结构。然而因为是新长出来的,根据生活常识可知si必定不会大于i时刻之前的树的大小。
DQS定义trie的子串为从根节点(1号节点)往下走到所有节点所构成的字符串的所有的后缀。DQS身为一个单身doge,常常取出其中一个子串送给妹子,然而他并不希望送给妹子两个相同的子串,所以他非常关心当前trie的本质不同的子串数目。
DQS有时还会去商店购买子串,若他在商店看上某个子串,他希望得知这个子串是否在自家阳台的trie上已经出现,若出现则出现了多少次。如果出现了,他就可以直接回家取trie上的子串辣!
然而DQS身为一个蒟蒻,看着自家阳台的trie树一天天在长大,他被如此众多的节点弄得眼花缭乱,于是他找到了IOI2016Au的你。他会告诉你自家trie树的成长历程,他希望你能够对于每一次询问都做出正确回复。

Input

第一行输入一个整数id,代表测试点编号。
接下来一行输入一个整数n0,表示初始树的大小。
接下来n0-1行,每行两个整数u,v和一个字符c,表示u号节点和v号节点之间有一条边,边上的字母为c。
接下来输入m表示有m组操作。
对于每一组,第一行输入一个整数opt。
若opt=1,则是一组询问,询问当前trie的本质不同的子串数目是多少。
若opt=2,则后面跟两个整数rt,si,表示以点rt为根向下长出一个子树,大小为si。
接下来si-1行,每行两个整数u,v和一个字符c,表示u号节点和v号节点之间有一条边,边上的字母为c。若长出子树之前当前树的大小是n,则这si-1点的编号分别为n+1,n+2…n+si-1。
若opt=3,则是一组询问,后面输入一个字符串S,询问字符串S在当前trie中的出现次数。 

Output

对于每个opt=1或3,输出一行表示答案。

Sample Input

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

Sample Output

3
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相关推荐

  1. BZOJ4545: DQS的trie 广义后缀自动机_LCT

    特别鸣神犇 fcwww 替我调出了无数个错误(没他的话我都快自闭了),祝大佬省选rp++ 板子题,给我写了一天QAQ...... 用 LCT 维护后缀树,暴力更新用 LCT 区间更新链即可 其实,在计 ...

  2. 「雅礼集训 2017 Day7」事情的相似度(后缀自动机+LCT+树状数组)

    description 点击查看题目内容 solution Step1 无脑建SAMSAMSAM 两个前缀的最长公共后缀就是parent−treeparent-treeparent−tree上两点的l ...

  3. BZOJ.2555.SubString(后缀自动机 LCT)

    题目链接 \(Description\) 给你一个字符串init,要求支持两个操作: (1)在当前字符串的后面插入一个字符串s (2)询问字符串s在当前字符串中出现了几次(作为连续子串) 强制在线. ...

  4. BZOJ 2555: SubString [后缀自动机 LCT]

    2555: SubString Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 2045  Solved: 583 [Submit][Status][ ...

  5. 【BZOJ4545】DQS的trie

    Description DQS的自家阳台上种着一棵颗粒饱满.颜色纯正的trie. DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符.并且,它拥有极强的生长力:某个i时刻 ...

  6. 【bzoj3926】[Zjoi20150]诸神眷顾的幻想乡 后缀自动机+trie

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  7. 从零开始の后缀自动机

    后缀自动机,一个处理字符串问题的神器.听起来很神圣,貌似很难写.其实代码实现并不复杂,萌新估计都能学会. 以前听学长们讲过好多次也看过陈立杰的课件,都不是很明白.今天终于弄明白了,就写一个让大家都能看 ...

  8. 【BZOJ3926】[Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机

    [BZOJ3926][Zjoi2015]诸神眷顾的幻想乡 Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝 ...

  9. BZOJ3277 串 【广义后缀自动机】

    Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身). Input 第一行两个整数n, ...

最新文章

  1. Windows Java、Tomcat、MySQL安装过程
  2. 36岁 计算机博士,36岁考博士
  3. Spring Boot 之spring.factories
  4. python slice函数怎么取列表的最后一个数_python slice函数_python中slice函数如何实现?...
  5. 操作系统学习---虚拟内存
  6. 高仿富途牛牛-组件化(五)-如何去管理炒鸡多的小窗口
  7. @程序员,如何解决开发和运维之间的固有隔阂?
  8. pytorch实现猫狗分类+数据集
  9. android多个声音输出,Android新增一个音频类型及双音频输出的实现
  10. 免费在线汉信码识别(Online Hanxin Decoder)
  11. 视频分割算法在移动端如何应用
  12. ASP.NET MVC里ModelState.IsValid总是true或者总是false
  13. 2.8.5Django --3 WEB框架
  14. 日志收集Agent,阴暗潮湿的地底世界
  15. js 倒计时算法及定时器的应用
  16. 央视《家有妙招》整理版,共125招,值得永远收藏
  17. 课件(Part 1, PJ)
  18. 图片文字怎么转换成文本?可以试试这三种途径
  19. GBN,SR,TCP协议实现可靠数据传输的原理
  20. 使用U盘安装windows系统教程

热门文章

  1. mvc与三层结构终极区别
  2. UML建模之数据建模
  3. muduo之channel
  4. springmvc三: REST
  5. ceph——rgw服务启不起来
  6. 一个查看UI5控件所有公有方法的小技巧
  7. Charles抓包https(测试app的双向认证)
  8. Android签名机制介绍:生成keystore.签名.查看签名信息等方法
  9. 创建租房网House脚本
  10. 借助二分法匹配时间戳实现快速查找日志内容