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#代码处理前台html标签拼接
之前一篇文章是写,JavaScript处理特殊字符拼接时截断问题.最近在处理公司老软件兼容性升级时碰到的一个类似的问题,这次是后台拼接字符串,前台.aspx页面显示的.中间走了两次弯路,在此记录一下. ...
- git与eclipse集成之代码提交
1.1. 代码提交 编码完成后,需要提交代码,例如新增文件git.txt 1.1.1. 提交代码到个人本地特性分支(commit) 选择工程,右键Team,Synchronize Wor ...
- CodeForces 931C Laboratory Work 水题,构造
*这种题好像不用写题解... 题意: 一个人要改动别人的实验记录,实验记录记录是一个集合 实验记录本身满足:$max(X)-min(X)<=2$ 改动结果要求: 1.新的集合平均值和之前的一样 ...
- elasticsearch5.0.1集群排错的几个思路总结
1.首先查看集群整体健康状态 # curl -XGET http://10.27.35.94:9200/_cluster/health?pretty { "cluster_name" ...
- python学习第9-10天,函数。
函数初识 为什么要使用函数? 函数最重要的目的是方便我们重复使用相同的一段程序. 将一些操作隶属于一个函数,以后你想实现相同的操作的时候,只用调用函数名就可以,而不需要重复敲所有的语句. 函数的定义与 ...
- python字符串str和字节数组bytes相互转化
1 引言 后续待补充 2 代码 b = b"Hello, world!" # bytes s = "Hello, world!" # string print( ...
- Solidity函数view,pure,constant的用法
函数访问权限:public,external,private,internal //子类可以得到父类下面的方法,父类用了public,external的话 pragma solidity ^; con ...
- Gradle更小、更快构建APP的奇淫技巧
本文已获得原作者授权同意,翻译以及转载原文链接:Build your Android app Faster and Smaller than ever作者:Jirawatee译文链接:Gradle更小 ...
- Java对象之间的深度复制拷贝
/* * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETA ...
- Confluence 6 为搜索引擎隐藏外部链接
为搜索引擎隐藏外部链接能够避免向你的站点添加垃圾信息.如果你启用了这个选项的话,任何插入到页面中的 URLs 和评论将会赋予 'nofollow' 属性,这个属性将会禁止搜索引擎进行索引. 快捷链接 ...