http://1572m36l09.iask.in:30808/problem/113

题目描述

你需要实现一种数据结构(可以参考标题)来实现以下操作:

1、在当前字符串的末尾加入一个字符;

2、删除当前字符串末尾的字符;

为了证明你进行了这些操作,每一次操作后,你需要输出当前字符串的不同子串个数以及在之前任意一个字符串中出现过的不同的字符串个数。

输入格式

一行一个长度为n字符串S。对于第k位,若Sk​是一个小写英文字符,表示在当前串的末尾插入Sk​。若是-,则表示删除末尾的字符。

输出格式

共n行,每行两个正整数,意义如题目描述所示。

​对于100%的数据,n≤200000,保证任何时候字符串的长度非负

先建出trie树,用bfs建出trie的SAM(dfs复杂度不对),具体就是加入trie上某个点之前把last置为父节点的last。trie上每个节点对应SAM上的一个点就是它的last(与SAM求子串出现次数类似)。

第一问就是求trie上一个点到根的链上所有点在parent树上的链并,用dfs序+set解决。

第二问就是当前已访问过的所有点在parent树上的链并。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
const int N=200005;
struct node
{int ch[26],fa,len;
}a[N*2];
int n,i,j,k,lst,cnt,w,ch[N][26],fa[N],Lst[N],num,q[2*N],bg,ed,head[2*N],adj[2*N],nxt[2*N],pt1[N],pt2[N],dep[N*2],d[N*2][20],h[N*2],id[N*2];
long long ans1[N],ans2[N],g[N],dis[N*2],ans,ANS;
char s[N];
set<int> st,ST;
set<int>::iterator ddq;
bool v[N*2];
inline void Clear(int id)
{a[id].fa=a[id].len=0;memset(a[id].ch,0,sizeof(a[id].ch));
}
void dfs(int x)
{h[++i]=x;id[x]=i;dis[x]+=a[x].len-a[a[x].fa].len;for(int y=head[x];y;y=nxt[y]){dep[adj[y]]=dep[x]+1;d[adj[y]][0]=x;dis[adj[y]]+=dis[x];dfs(adj[y]);}
}
int lca(int a,int b)
{int c,y;if(dep[a]<dep[b])swap(a,b);for(c=dep[a]-dep[b],y=0;c;c>>=1,++y)if(c&1)a=d[a][y];if(a==b)return a;for(c=19;c>=0;--c)if(d[a][c]!=d[b][c])a=d[a][c],b=d[b][c];return d[a][0];
}
void add(int x)
{int y=1,z=1;ddq=st.upper_bound(id[x]);if(ddq!=st.end())y=lca(x,h[*ddq]);ddq--;z=lca(x,h[*ddq]);if(dep[z]>dep[y])y=z;ans+=dis[x]-dis[y];st.insert(id[x]);if(!v[x]){v[x]=true;ddq=ST.upper_bound(id[x]);if(ddq!=ST.end())y=lca(x,h[*ddq]);ddq--;z=lca(x,h[*ddq]);if(dep[z]>dep[y])y=z;ANS+=dis[x]-dis[y];ST.insert(id[x]);}
}
void del(int x)
{st.erase(id[x]);int y=1,z=1;ddq=st.upper_bound(id[x]);if(ddq!=st.end())y=lca(x,h[*ddq]);ddq--;z=lca(x,h[*ddq]);if(dep[z]>dep[y])y=z;ans-=dis[x]-dis[y];
}
int main()
{freopen("c.in","r",stdin);freopen("c.out","w",stdout);scanf("%s",s+1);num=1;Lst[1]=1;lst=cnt=1;Clear(1);for(i=1,k=1;s[i];++i){if(s[i]>='a'&&s[i]<='z'){j=s[i]-'a';if(ch[k][j]){k=ch[k][j];continue;}ch[k][j]=++num;fa[num]=k;k=num;}elsek=fa[k];}for(i=0;i<26;++i)if(ch[1][i]){q[++ed]=ch[1][i];h[ed]=i;}bg=1;while(bg<=ed){j=h[bg];lst=Lst[fa[q[bg]]];int p,np;p=lst;np=lst=++cnt;Clear(cnt);a[np].len=a[p].len+1;pt1[q[bg]]=np;for(;p&&!a[p].ch[j];p=a[p].fa)a[p].ch[j]=np;if(!p)a[np].fa=1;else{int q=a[p].ch[j];if(a[q].len==a[p].len+1)a[np].fa=q;else{int nq=++cnt;Clear(cnt);a[nq]=a[q];a[nq].len=a[p].len+1;//ans2[i]+=a[a[q].fa].len-a[nq].len;//ans2[i]+=a[nq].len-a[a[nq].fa].len;a[np].fa=a[q].fa=nq;for(;p&&a[p].ch[j]==q;p=a[p].fa)a[p].ch[j]=nq;}}Lst[q[bg]]=lst;//printf("%d\n",lst);for(i=0;i<26;++i)if(ch[q[bg]][i]){q[++ed]=ch[q[bg]][i];h[ed]=i;}++bg;}for(i=2;i<=cnt;++i){adj[i-1]=i;nxt[i-1]=head[a[i].fa];head[a[i].fa]=i-1;//printf("%d %d\n",a[i].fa,i);
    }i=0;dfs(1);for(i=1;(1<<i)<cnt;++i)for(j=1;j<=cnt;++j)if(d[j][i-1])d[j][i]=d[d[j][i-1]][i-1];st.insert(1);ST.insert(1);for(i=1,k=1;s[i];++i){if(s[i]>='a'&&s[i]<='z'){j=s[i]-'a';k=ch[k][j];add(pt1[k]);//if(pt2[k])//add(pt2[k]);
        }else{del(pt1[k]);//if(pt2[k])//del(pt2[k]);k=fa[k];}ans1[i]=ans;ans2[i]=ANS;}for(i=1;s[i];++i)printf("%lld %lld\n",ans1[i],ans2[i]);return 0;
}

转载于:https://www.cnblogs.com/pthws/p/11154818.html

FZOJβ #113 后缀平衡树相关推荐

  1. 3682: Phorni 后缀平衡树 线段树

    国际惯例的题面: 考虑如果没有强制在线我们能怎么水掉这个题,先构造出字符串,各种方法求一下后缀数组,然后线段树维护区间rank最小的位置即可. 然而他要求强制在线,支持插入后缀,并比较后缀大小(求ra ...

  2. 【bzoj2555】Substring【后缀平衡树入门】

    传送门 (bzoj上不去我也很无奈啊) 题意:维护一个字符串,支持后面加字符串,给定串询问出现次数.强制在线. 数据范围:暴力跑不过 前置知识:重量平衡树 众所周知,平衡树都用了一些策略保证平衡. 平 ...

  3. [学习笔记]后缀平衡树

    后缀数组+平衡树=后缀平衡树 支持动态插入字符(只能往前插入),即插入一个后缀,维护所有后缀的排名 插入后缀找到位置?平衡树上二分 法一: 哈希+二分,太慢 法二: 第一个字符不同,已经可以比较,否则 ...

  4. bzoj4768: wxh loves substring //后缀平衡树

    bzoj4768: 2555加强版之wxh loves substring 题意 给出一个字符串,要求资瓷: 在末尾添加/删除字符: 询问一个串的出现次数. 原串长与变化长度之和<=800000 ...

  5. k8s跑一个nginx-app体验

    kubectl run 并不是直接创建一个 Pod,而是先创建一个 Deployment 资 源(replicas=1),再由与 Deployment 关联的 ReplicaSet 来自动创建 Pod ...

  6. 【BZOJ3224】【codevs4543】【tyvj1728】普通平衡树,第一次的splay

    传送门1 传送门2 传送门3 写在前面:woc--woc--大家知道为什么这么久没写题解了吧 思路:不会用指针千万别用!千万别手贱多写函数!千万多调用splay! 感谢http://blog.csdn ...

  7. BZOJ3682 : Phorni

    后缀平衡树+线段树. $O(1)$比较大小的标号法真是强大. #include<cstdio> #include<cmath> #define N 300010 #define ...

  8. 纪中集训 Day 3

    这几天一直坚持写blog= =加油吧!! 早上醒来,说了"我要AK"(其实只是蒟蒻的妄想罢了QAQ) 然后为了不立flag,改成了我要rank 1 然后依旧是有一题不会做QAQ 好 ...

  9. 【洛谷P4719】动态DP【LCT】【矩阵】

    之前的后缀平衡树其实没完,只是过于鬼畜就弃了 传送门 题意:带修改点权的最大独立集 N≤1e5N \leq 1e5N≤1e5 一个没啥用的模板,不过适合练习LCT 先写出方程 f(u,0)=∑v∈so ...

最新文章

  1. LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android
  2. ISA SERVER 2004 对多重网络支持功能简述
  3. SQL中删除重复的行(重复数据),只保留一行 转
  4. torchvision.datasets.ImageFolder使用详解
  5. CVPR 2020 Oral | 旷视提出目前最好的密集场景目标检测算法:一个候选框,多个预测结果...
  6. ButterKnife View 注入
  7. SVN项目提交错误,回退版本(svn项目回退指定版本)
  8. jdk6或者7Base64转码与解码
  9. ARDUINO LCD显示简单的汉字、符号(保姆级教程!)
  10. 智能电动自行车充电桩系统解决方案
  11. java 时区 mysql 时区:时区在程序和数据库中的作用及其机制
  12. 条码打印机换碳带的方法
  13. CodeForces 954A Diagonal Walking
  14. 【Java写的碰碰球游戏(2) 】
  15. Dynamic Topic Models的Python实现
  16. ios:应用发布App Store流程
  17. FeignClient调用 Cannot deserialize instance of `java.lang.Boolean` out of START_OBJECT token to
  18. 在eclipse中用java代码测试是否成功连接数据库
  19. 反恐精英代码_游戏《反恐精英:全球攻势》《军团要塞2》源代码遭泄露
  20. 寻址 far near

热门文章

  1. 嵌入式linux工控板,基于Linux的ARM9工业控制板设计
  2. token防止表单重复提交
  3. eval 是做什么的?
  4. [实践篇]13.8 如何解析gcore?
  5. SPSS—回归—多元线性回归结果分析(二)
  6. gcov的实现原理简介
  7. Linux:快速查看IP地址及修改IP地址
  8. 机器学习中数据预处理——标准化/归一化方法(scaler)
  9. java 处理物料清单_ERP之物料清单(BOM)
  10. c/c++ substr()函数