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 后缀自动机(原理题)
比较考验对后缀自动机构建过程的理解. 之前看题解写的都是树链的并,但是想了想好像可以直接撤销,复杂度是线性的. 自己想出来的,感觉后缀自动机的题应该不太能难倒我~ 注意:一定要手画一下后缀自动机的构建 ...
随机推荐
- HDU contest808 ACM多校第7场 Problem - 1008: Traffic Network in Numazu
首先嘚瑟一下这场比赛的排名:59 (第一次看到这么多 √ emmmm) 好了进入正文QAQ ...这道题啊,思路很清晰啊. 首先你看到树上路径边权和,然后还带修改,不是显然可以想到 树剖+线段树 维护 ...
- webstorm设置VCS:版本控制顶部按钮
说明: 每次都在这坑一下,浪费时间,百度只指出在哪,并没有说怎么调出来 我用的版本是10,点击下面的选项按操作设置就可以了 红色箭头:从服务器获取最新代码: 绿色箭头:提交: 白色箭头:撤销
- disk2vhd-----将windows系统转换成虚拟镜像格式
工具介绍 下载url:http://technet.microsoft.com/en-us/sysinternals/ee656415.aspx disk2vhd是一个非常小的P2V转换工具,可以将你 ...
- awk-for循环简单用法
文本: [root@VM_0_84_centos ~]# cat sshd.txt 1 2 3 4 5 6 7 8 9 循环打印上述文本 for 循环的固定格式 i=1设置i的初始变量 i< ...
- 微信小程序—获取用户网络状态和设备的信息
这个是一个简易教程,按照他的步骤下载好了,打开界面看到的效果是如下的:
- js——prototype、__proto__、constructor
Object 1. Object是一个函数(typeof O ...
- PID控制器开发笔记之三:抗积分饱和PID控制器的实现
积分作用的引入是为了消除系统的静差,提高控制精度.但是如果一个系统总是存在统一个方向的偏差,就可能无限累加而进而饱和,极大影响系统性能.抗积分饱和就是用以解决这一问题的方法之一.这一节我们就来实现抗积 ...
- Windows添加.NET Framework 3.0 NetFx3 失败 - 状态为:0x800f0950
原文链接:https://answers.microsoft.com/zh-hans/insider/forum/all/win10-dism%E9%94%99%E8%AF%AF-0x800f0950 ...
- Confluence 6 订阅所应用的所有小工具
你可以从你的 Jira, Bamboo,FishEye 或 Crucible 站点中订阅所有的小工具到你的 Confluence 小工具目录中.用户可以为他们的页面查找和选择小工具. 希望订阅其他站点 ...
- iframe与主框架跨域相互访问方法
iframe 与主框架相互访问方法 http://blog.csdn.net/fdipzone/article/details/17619673/ 1.同域相互访问 假设A.html 与 b.htm ...