传送门

没想出来→_→

首先不难看出要差分之后计算不相交也不相邻的相等子串对数,于是差分之后建SAM,在parent树上用线段树合并维护endpos集合,然后用启发式合并维护一个节点对另一个节点的贡献,于是总的时间复杂度为\(O(n\log^2n)\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define IT vector<int>::iterator
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
#define gg(u) for(IT it=f[u].begin();it!=f[u].end();++it)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=6e5+5;
struct eg{int v,nx;}e[N];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int fa[N],l[N],a[N],rt[N];map<int,int>ch[N];
struct node{int s,ls,rs;ll xs;}t[N<<5];vector<int>*f[N],tmp[N];
int n,m,ctot,cnt,las;ll ans;
void ins(int c){
int p=las,np=++cnt;las=np,l[np]=l[p]+1;
for(;p&&!ch[p].count(c);p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+1;
ch[nq]=ch[q],fa[nq]=fa[q],fa[np]=fa[q]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
void update(int &p,int l,int r,int x){
if(!p)p=++ctot;++t[p].s,t[p].xs+=x;
if(l==r)return;
int mid=(l+r)>>1;
x<=mid?update(t[p].ls,l,mid,x):update(t[p].rs,mid+1,r,x);
}
int qaqs(int p,int l,int r,int ql,int qr){
if(!p)return 0;if(ql<=l&&qr>=r)return t[p].s;
int mid=(l+r)>>1,res=0;
if(ql<=mid)res+=qaqs(t[p].ls,l,mid,ql,qr);
if(qr>mid)res+=qaqs(t[p].rs,mid+1,r,ql,qr);
return res;
}
inline int querys(R int p,R int l,R int r){return (l>r||r<1||l>n)?0:qaqs(p,1,n,l,r);}
ll qaqxs(int p,int l,int r,int ql,int qr){
if(!p)return 0;if(ql<=l&&qr>=r)return t[p].xs;
int mid=(l+r)>>1;ll res=0;
if(ql<=mid)res+=qaqxs(t[p].ls,l,mid,ql,qr);
if(qr>mid)res+=qaqxs(t[p].rs,mid+1,r,ql,qr);
return res;
}
inline ll queryxs(R int p,R int l,R int r){return (l>r||r<1||l>n)?0:qaqxs(p,1,n,l,r);}
int merge(int x,int y){
if(!x||!y)return x|y;
t[x].s+=t[y].s,t[x].xs+=t[y].xs;
t[x].ls=merge(t[x].ls,t[y].ls),t[x].rs=merge(t[x].rs,t[y].rs);
return x;
}
void dfs(int u){
int k=l[u];
go(u){
dfs(v);if(f[u]->size()<f[v]->size())swap(f[u],f[v]),swap(rt[u],rt[v]);
gg(v){
int x=*it;
ll A=1ll*querys(rt[u],x-k-1,x-2)*(x-1)-queryxs(rt[u],x-k-1,x-2)+1ll*querys(rt[u],1,x-k-2)*k;
ll B=1ll*queryxs(rt[u],x+2,x+k+1)-1ll*querys(rt[u],x+2,x+k+1)*(x+1)+1ll*querys(rt[u],x+k+2,n)*k;
ans+=A+B,f[u]->push_back(x);
}rt[u]=merge(rt[u],rt[v]);
}
}
int main(){
// freopen("testdata.in","r",stdin);
n=read();
fp(i,1,n)a[i]=read();
fp(i,1,n-1)a[i]=a[i+1]-a[i],f[i]=&tmp[i];
ans=1ll*n*(n-1)>>1;
--n,las=cnt=1;
fp(i,1,n)ins(a[i]),f[las].push_back(i),update(rt[las],1,n,i);
fp(i,2,cnt)add(fa[i],i);
dfs(1);printf("%lld\n",ans);
return 0;
}

P5161 WD与数列(后缀自动机+线段树合并)的更多相关文章

  1. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  2. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  3. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  4. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  5. 【BZOJ4556】[TJOI2016&HEOI2016] 字符串(后缀自动机+线段树合并+二分)

    点此看题面 大致题意: 给你一个字符串\(s\),每次问你一个子串\(s[a..b]\)的所有子串和\(s[c..d]\)的最长公共前缀. 二分 首先我们可以发现一个简单性质,即要求最长公共前缀,则我 ...

  6. bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并)

    bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并) bzoj Luogu 给出一个字符串 $ S $ 及 $ q $ 次询问,每次询问一个字符串 $ T $ ...

  7. BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并

    题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...

  8. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  9. 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 657  Solved: 274[Su ...

随机推荐

  1. 函数柯里化 curry

    一.函数柯里化的特性: (1)参数复用 $.ajax // 示例一 function ajax(type,url,data) { var xhr = new XMLHttpRequest(); xhr ...

  2. JAVASE学习笔记:第八章 经常使用类Util工具包之日期类、数字类

    一.Date类   日期类 所在java.Util工具包     before(Date when)   測试此日期是否在指定日期之前. getDay()  获取星期的某一天     getDate( ...

  3. 第8章4节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-启动AndroidDebugBridge

    上一节我们看到在启动AndroidDebugBridge的过程中会调用其start方法,而该方法会做2个基本的事情: 715行startAdb:开启AndroidDebugBridge 722-723 ...

  4. Arcgis Engine(ae)接口详解(2):featureClass查询

    //属性查询~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //IQueryFilter代表查询条件,QueryFilterClass代表只限于属性查询(就是没有空间查询) ...

  5. windows下安装RubbitMq

    1.下载 下载 rabbitMQ :http://www.rabbitmq.com/download.html,安装rabbitmq需要erlang,下载erlang:http://www.erlan ...

  6. apt仓库以及apt-get分析

    1 debian repository 参考:https://wiki.debian.org/DebianRepository 1.1 版本代号 sid,still in development,该版 ...

  7. Golang 现有的哲学中,要求你尽量手工处理所有的错误返回

    更优雅的 Golang 错误处理 - Go语言中文网 - Golang中文社区 https://studygolang.com/articles/9407

  8. hdu 1757 A Simple Math Problem (矩阵高速幂)

    和这一题构造的矩阵的方法同样. 须要注意的是.题目中a0~a9 与矩阵相乘的顺序. #include <iostream> #include <cstdio> #include ...

  9. hihoCoder 1582 Territorial Dispute 【凸包】(ACM-ICPC国际大学生程序设计竞赛北京赛区(2017)网络赛)

    #1582 : Territorial Dispute 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 In 2333, the C++ Empire and the Ja ...

  10. 在docker里查看java进程

    先使用命令查看docker的运行进程 docker ps [root@localhost logs]# docker ps CONTAINER ID        IMAGE             ...