神奇的结论:

一个字符串的所有回文后缀的长度,可以形成\(k\)个等差数列,\(k\)是\(log\)级的

考虑前\(R\)个字符组成的字符串,对于一个等差数列,假设组成这个等差数列的回文串,最短的叫\(a\),最长的叫\(b\) 对于右端点是\(R\)的询问,左端点在\([b\)上一次出现的位置开头\(+1\),\(a\)的开头\(]\)这一段区间的话,\(ans\)要\(+1\)

不会证 自己画了画感觉好像挺对的

知道这个之后只要建出来回文树 询问按右端点排序 每做到一个点回答关于它的询问 最后一次出现的位置用线段树维护 区间加用树状数组维护就做完了

#include<bits/stdc++.h>
using namespace std;
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pa pair<int,int>
#define mod 1000000007
#define ll long long
#define mk make_pair
#define pb push_back
#define lb double
#define fi first
#define se second
#define cl(x) memset(x,0,sizeof x)
#ifdef Devil_Gary
#define bug(x) cout<<(#x)<<" "<<(x)<<endl
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define bug(x)
#define debug(...)
#endif
const int INF = 0x7fffffff;
const int N=3e5+5;
const int M=1e6+5;
/*
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
inline int read(){
int x=0,rev=0,ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return rev?-x:x;
}
struct Edge{
int v,_nxt;
}e[N];
char s[N];
int head[N],lst,cnt=1,n,m,id,ans[M],Ans,tot,dd[N],c[N][26],L[M],diff[N],fail[N],nxt[N],pre[M],len[N],h[N],in[N],out[N],sum[N],t[N<<2];
int extend(int x,int n){
int p=lst;
while(s[n-len[p]-1]!=s[n]) p=fail[p];
if(!c[p][x]){
int now=++cnt,k=fail[p];
len[now]=len[p]+2;
while(s[n-len[k]-1]!=s[n]) k=fail[k];
fail[now]=c[k][x],c[p][x]=now;
diff[now]=len[now]-len[fail[now]];
if(diff[now]==diff[fail[now]]) nxt[now]=nxt[fail[now]];
else nxt[now]=now;
}
return lst=c[p][x];
}
void add(int u,int v){
e[++tot].v=v,e[tot]._nxt=head[u],head[u]=tot;
}
void build(){
memset(h,0,sizeof h);
for(int i=0;i<=cnt;i++) if(i!=1) add(fail[i],i);
}
void dfs(int x){
in[x]=++id;
for(int i=head[x];i;i=e[i]._nxt){
int j=e[i].v;
dfs(j);
}
out[x]=id;
}
void modify(int pos,int l,int r,int x,int v){
if(l==r) return void(t[pos]=v);
int mid=l+r>>1;
if(x<=mid) modify(pos<<1,l,mid,x,v);
else modify(pos<<1|1,mid+1,r,x,v);
t[pos]=max(t[pos<<1],t[pos<<1|1]);
}
int Query(int pos,int l,int r,int nl,int nr){
if(nl<=l&&r<=nr) return t[pos];
int mid=l+r>>1;
if(nr<=mid) return Query(pos<<1,l,mid,nl,nr);
if(nl>mid) return Query(pos<<1|1,mid+1,r,nl,nr);
return max(Query(pos<<1,l,mid,nl,nr),Query(pos<<1|1,mid+1,r,nl,nr));
}
#define lowbit(x) x&(-x)
void Add(int x,int v){
for(int i=x;i<=n;i+=lowbit(i)) sum[i]+=v;
}
int ask(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=sum[i];
// cout<<ans<<endl;
return ans;
}
int main(){
#ifdef Devil_Gary
freopen("gugu.in","r",stdin);
#endif
n=read(),m=read(),scanf("%s",s+1),fail[0]=fail[1]=1,len[1]=-1;
for(int i=1;i<=n;i++) dd[i]=extend(s[i]-'a',i);
build(),dfs(1);
for(int i=1,k;i<=m;i++) L[i]=read(),k=read(),pre[i]=h[k],h[k]=i;
for(int i=1;i<=n;i++){
int x=dd[i];
for(int j=x;j;j=fail[nxt[j]]){
/* bug(j);
bug(id);*/
Add(max(1,Query(1,1,id,in[j],out[j])-len[j]+2),1);
/* bug(j);
bug(i-len[nxt[j]]+2);*/
Add(i-len[nxt[j]]+2,-1);
}
modify(1,1,id,in[x],i);
for(int j=h[i];j;j=pre[j]) ans[j]=ask(L[j]);
}
for(int i=1;i<=m;i++) (Ans+=(ll)ans[i]*i%mod)%=mod;
printf("%d\n",Ans);
}

BZOJ5384 有趣的字符串题 回文树的更多相关文章

  1. 字符串hash+回文树——hdu6599

    拖了很久才补的回文树,感觉网上的博客都是一个做法..回文树统计不同种类的回文串出现次数,然后用字符串hash来判每个回文子串是否符合要求 #include<bits/stdc++.h> u ...

  2. Palindrome Mouse(2019年牛客多校第六场C题+回文树+树状数组)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 问\(s\)串中所有本质不同的回文子串中有多少对回文子串满足\(a\)是\(b\)的子串. 思路 参考代码:传送门 本质不同的回文子串肯定是要 ...

  3. UVALive-7041(回文树

    题意:给你两个字符串,问你有多少对公共回文串. 思路:先对a字符串建回文树.然后再把b字符串加进去就好了. #include<cstdio> #include<cmath> # ...

  4. 2014-2015 ACM-ICPC, Asia Xian Regional Contest G The Problem to Slow Down You 回文树

    The Problem to Slow Down You Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjud ...

  5. [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  6. UESTC - 1999 也许这是唯一能阻止乐爷AK的方法( Just for Fun )(回文树)

    https://vjudge.net/problem/UESTC-1999 题意 对于一个初始为空的字符串S,你可以进行以下两种操作: 1. 在S的末尾加一个小写字母. 2. 移除S的最后一个字母. ...

  7. BZOJ - 3676 回文串 (回文树)

    https://vjudge.net/problem/HYSBZ-3676 题意 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s ...

  8. 回文树&后缀自动机&后缀数组

    KMP,扩展KMP和Manacher就不写了,感觉没多大意思.   之前感觉后缀自动机简直可以解决一切,所以不怎么写后缀数组.   马拉车主要是通过对称中心解决问题,有的时候要通过回文串的边界解决问题 ...

  9. Gym - 101806Q:QueryreuQ(回文树)

    A string is palindrome, if the string reads the same backward and forward. For example, strings like ...

随机推荐

  1. art 校准时设备端操作

    (1)准备所需文件art.ko  和 nart.out (2)配置设备的IP地址(例如:192.168.2.122),使之能与本地PC通信 (3)上传文件到设备 cd /tmp tftp -g -r ...

  2. 超级wifi

    超级wifi (super wi-fi)是相对于现有的wifi提出的改进版,执行响应的 802.11af标准. 802.11af 标准是2014年2月提出的,它的主要特点是"建议在电视频率之 ...

  3. (常用)re模块

    re模块(正则)#re:一些带有特殊含义的符号或者符号的组合#为什么要用re:一堆字符串中找到你所需要的内容,过滤规则是什么样,通过re模块功能来告诉计算机你的过滤规则#应用:在爬虫中最为常用:使用爬 ...

  4. curl, wget常用选项

    使用指定的http代理,配合md5sum 对于检查源站与cdn节点资源是否一致很有效 curl -o a.jpg -x http://pbcdn.xximg1.com/v6/global2015/im ...

  5. expdp和impdp快速导出导入,不用创建虚拟目录

    expdp 和impdp不用创建虚拟目录:在cmd直接   expdp 用户名/密码 回车 就导出了,(如果提示输入用户名和密码就输入).再将导出的文件放在oracle默认的dpdump文件夹里面,然 ...

  6. jquery实现右键菜单

    <!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/h ...

  7. 分享我对JS插件开发的一些感想和心得

    本文阅读目录: •起因•如何开发一个轻量级的适用性强的插件•总结 起因 如果大家平时做过一些前端开发方面的工作,一定会有这样的体会:页面需要某种效果或者插件的时候,我们一般会有两种选择: 1.上网查找 ...

  8. 扩展欧几里得,解线性同余方程 逆元 poj1845

    定理:对于任意整数a,b存在一堆整数x,y,满足ax+by=gcd(a,b) int exgcd(int a,int b,int &x,int &y){ ){x=,y=;return ...

  9. pytest十五:pytest-html 生成 html 报告

    pytest-HTML 是一个插件,pytest 用于生成测试结果的 HTML 报告.兼容 Python 2.7,3.6 pytest-html1.github 上源码地址[https://githu ...

  10. c++ primer 学习杂记3【标准IO库】

    第8章 标准IO库 发现书中一个错误,中文版p248 流状态的查询和控制,举了一个代码例子: int ival; // read cin and test only for EOF; loop is ...