BZOJ5084[hashit]
题解:
后缀自动机
我们可以通过建立trie
把询问变成询问一些点的并
把trie建立成SAM和广义SAM基本相同,就是在父亲和儿子之间连边
然后就变成了询问树链的并
我们可以发现答案=sigma dis[i] -sigma(dis[lca(i,i+1)])
其中i和i+1dfs序相邻
可以通过set来维护
***
把倍增的预处理写在了dfs前
把&&写成了&
代码:
#include <bits/stdc++.h>
#define rint register int
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
#define ll long long
using namespace std;
const int N=2e5;
char s[N];
int len,cnt,son[N][],pos[N],cnt2;
struct hz{
int ch[N][],node,len[N],fa[N];
hz()
{
node=;
}
int extend(int c,int z)
{
int lst=z;
int f=lst;
if (ch[f][c]&&len[ch[f][c]]==len[f]+)
{
lst=ch[f][c];
return(lst);
}
int p=++node; lst=p;
len[p]=len[f]+; //size[p][pl]=1;
while (f&&!ch[f][c]) ch[f][c]=p,f=fa[f];
if (!f) { fa[p]=; return(p);};
int x=ch[f][c],y=++node;
if (len[f]+==len[x]) {fa[p]=x; node--;return(p);}
len[y]=len[f]+; fa[y]=fa[x]; fa[x]=fa[p]=y;
memcpy(ch[y],ch[x],sizeof(ch[x]));
while (f&&ch[f][c]==x) ch[f][c]=y,f=fa[f];
return(p);
}
void build(int x)
{
rep(i,,)
if (son[x][i])
{
pos[son[x][i]]=extend(i,pos[x]);
build(son[x][i]);
}
}
}S;
int l,head[N],bz[N][],dfn[N],rl[N],dis[N],fa[N],dep[N],zt[N];
struct re{
int a,b;
}a[N];
void arr(int x,int y)
{
a[++l].a=head[x];
a[l].b=y;
head[x]=l;
}
void dfs(int x,int y)
{
int u=head[x]; bz[x][]=y; dfn[x]=++cnt2; rl[cnt2]=x;
dep[x]=dep[y]+;
dis[x]=dis[y]+S.len[x]-S.len[y];
while (u)
{
int v=a[u].b;
dfs(v,x);
u=a[u].a;
}
}
set<int> M;
set<int>::iterator it;
int lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
dep(i,,)
if (dep[bz[x][i]]>=dep[y]) x=bz[x][i];
if (x==y) return(x);
dep(i,,)
if (bz[x][i]!=bz[y][i]) x=bz[x][i],y=bz[y][i];
return(bz[x][]);
}
int main()
{
freopen("1.in","r",stdin);
freopen("3.out","w",stdout);
scanf("%s",s);
len=strlen(s);
int now=;
cnt=;
rep(i,,len-)
{
if (s[i]=='-') now=fa[now];
else
{
if (!son[now][s[i]-'a']) son[now][s[i]-'a']=++cnt,fa[cnt]=now;
now=son[now][s[i]-'a'];
}
}
pos[]=; S.build();
for(int i=;i<=S.node;i++) arr(S.fa[i],i);
dfs(,);
rep(i,,)
rep(j,,S.node) bz[j][i]=bz[bz[j][i-]][i-];
ll ans=; now=;
int cnt3=;
rep(i,,len-)
{
if (s[i]=='-')
{
int x=,y=;
ans-=dis[now];
it=M.find(dfn[now]); it++;
if (it!=M.end()) x=rl[*it]; it--;
if (it!=M.begin()) y=rl[*--it];
M.erase(dfn[now]);
if (x) ans+=dis[lca(now,x)];
if (y) ans+=dis[lca(now,y)];
if (x&&y) ans-=dis[lca(x,y)];
now=zt[--cnt3];
} else
{
int x=,y=;
now=S.ch[now][s[i]-'a'];
zt[++cnt3]=now;
ans+=dis[now];
it=M.insert(dfn[now]).first;
it++;
if (it!=M.end()) x=rl[*it]; it--;
if (it!=M.begin())
{
y=rl[*--it];
}
if (x) ans-=dis[lca(now,x)];
if (y) ans-=dis[lca(now,y)];
if (x&&y) ans+=dis[lca(x,y)];
// cout<<lca(pos[now],x)<<" "<<lca(pos[now],y)<<" "<<x<<" "<<y<<endl;
}
printf("%lld\n",ans);
}
return ;
}
BZOJ5084[hashit]的更多相关文章
- 【SAM】bzoj5084: hashit
做得心 力 憔 悴 Description 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 Input 一行一个字符 ...
- bzoj5084 hashit 广义SAM+树链的并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5084 题解 考虑平常对于静态问题,我们应该如何用 SAM 求本质不同的子串个数. 对于一个常规 ...
- Noip前的大抱佛脚----赛前任务
赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...
- SAM(后缀自动机)总结
“写sam是肯定会去写的,这样才学的了字符串,后缀数组又不会用 >ω<, sam套上数据结构的感觉就像回家一样! 里面又能剖分又能线段树合并,调试又好调,我爱死这种写法了 !qwq” SA ...
- 【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set
题目描述 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 输入 一行一个字符串Q,表示对S的操作 如果第i个字母是小 ...
- 【bzoj5084】 hashit(广义SAM+set)
题面 传送门 题解 后缀平衡树是个啥啊我不会啊-- 那么我们来考虑一下\(SAM\)的做法好了 不难发现它的本义是要我们维护一棵\(trie\)树,并求出\(trie\)树上每一个节点到根的这段串的不 ...
- 【BZOJ5084】hashit(后缀自动机水过)
点此看题面 大致题意: 每次在字符串后面加入或删除一个字符,求本质不同的子串个数. 后缀自动机 先说明,此题后缀自动机的确能过. 但我的后缀自动机比较弱,遇上一个较强的\(Hack\)数据就被卡掉了. ...
- bzoj 5084: hashit
Description 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 Solution 先忽略删除操作,建出最终的 ...
- BZOJ 5084: hashit 后缀自动机(原理题)
比较考验对后缀自动机构建过程的理解. 之前看题解写的都是树链的并,但是想了想好像可以直接撤销,复杂度是线性的. 自己想出来的,感觉后缀自动机的题应该不太能难倒我~ 注意:一定要手画一下后缀自动机的构建 ...
随机推荐
- 设计模式C++学习笔记之四(Multition多例模式)
多例模式,这个在GOF的模式设计里没有提到,但在实际工作中确实会用到.更详细的内容及说明可以参考原作者博客:cbf4life.cnblogs.com. 4.1.解释 main(),客户 略 说明: ...
- 初次认识dedecms和帝国cms内容管理系统
近乎完美的内容模块管理 强大的内容管理系统,细致入微 其原理都是 先建立一个 模板系统 然后动态生成静态页面 注意各个板块和栏目的设置 在迁移网站的时候 尤其需要注意的是 系统参数的 根目录 需要及 ...
- linux 新机器的配置(git + nodejs+ mongodb)
安装nodejs: wget https://nodejs.org/dist/v6.9.5/node-v6.9.5-linux-x64.tar.xz tar xvf node-v6.9.5-linux ...
- datepicker 属性设置 以及方法和事件
DatePicker支持鼠标点选日期,同时还可以通过键盘控制选择: page up/down - 上一月.下一月 ctrl+page up/down - 上一年.下一年 ctrl+home - 当前月 ...
- SQL Server 2017 安装详解
SQL server 2017下载链接:https://pan.baidu.com/s/1FSzqJfHQAa0QpZ_fObrfjQ 提取码:1xvb 1.双击iso镜像文件 打开setup ...
- Dubbo原理解析-Dubbo内核实现之SPI简单介绍
转自:https://blog.csdn.net/quhongwei_zhanqiu/article/details/41577159 Dubbo 采用微内核+插件体系,使得设计优雅,扩展性强.那所谓 ...
- STM32L476应用开发之六:电池SOC检测
便携式设备由于使用需求而配备了锂电池,但使用过程中需要掌握电源的状态才能保证设备正常运行.而且在电池充放电的过程中,监控电池的充放电状态也是保证设备安全的需要. 1.硬件设计 电池SOC检测是一个难题 ...
- SpringMVC简介
一.SpringMVC 是什么? 后续编辑,先上Demo>> SpringMVCDemo
- Confluence 6 管理协同编辑
协同编辑能够让项目小组中的协同合作达到下一个高度.这个页面对相关协同编辑中的问题进行了讨论,能够提供给你所有希望了解的内容. 进入 Collaborative editing 页面来获得项目小组是如何 ...
- Confluence 6 从生产环境中恢复一个测试实例
请参考 Restoring a Test Instance from Production 页面中的内容获得更多完整的说明. 很多 Confluence 的管理员将会使用生产实例运行完整数据和服务的 ...