• 题意:给一个长n的字符串S,q组询问,每组给两个集合A,B。求集合A中的点和集合B中的点所有组合情况的lcp的和。
  • 思路:

    好像比较常规,可是代码能力差还是调了1.5h。主要还是虚树板子不熟(加入的时候点要去重)

    SAM+虚树+虚树上dp

    两个后缀的lca相当于后缀树上两个对应节点的LCA的len。

    dp就统计每个点为lca的方案数*len[lca]
  • code:
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
char s[N];
typedef long long ll;
int lg[N],a[N],b[N],d[N],pos[N],nxt[N],to[N],head[N],ecnt;
void add_edge(int u,int v) {nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
struct SAM {
int f[N][21],dep[N],ch[N][27],t[N],len[N],lst,num,par[N],sz[N],Head[N],To[N],Nxt[N],Ecnt,In[N],Out[N],Time;
SAM() {lst=num=1;}
void Add_edge(int u,int v) {Nxt[++Ecnt]=Head[u];To[Ecnt]=v;Head[u]=Ecnt;}
int Insert(int x) {
int p=lst,np=++num;lst=np;len[np]=len[p]+1;sz[np]=1;
for(;!ch[p][x];p=par[p]) ch[p][x]=np;
if(!p) {par[np]=1;return np;}
int q=ch[p][x];
if(len[q]==len[p]+1) {par[np]=q;return np;}
int nq=++num;par[nq]=par[q];len[nq]=len[p]+1;
for(int j=0;j<26;j++)ch[nq][j]=ch[q][j];
par[q]=par[np]=nq;
for(;ch[p][x]==q;p=par[p])ch[p][x]=nq;
return np;
}
void dfs(int u) {
In[u]=++Time;
for(int i=Head[u];i;i=Nxt[i]) {
int v=To[i];
dep[v]=dep[u]+1;f[v][0]=u;
for(int j=1;j<=lg[dep[v]];j++) f[v][j]=f[f[v][j-1]][j-1];
dfs(v);
}
Out[u]=Time;
}
void bd_Fail() {
for(int i=1;i<=num;i++) if(par[i])Add_edge(par[i],i);
dfs(1);
}
int Lca(int u,int v) {
if(dep[u]<dep[v])swap(u,v);
int k=dep[u]-dep[v];for(int i=0;i<=lg[k];i++)if((1<<i)&k)u=f[u][i];
if(u==v) return u;
for(int i=lg[dep[u]];i>=0;i--) if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
return f[u][0];
}
}A;
bool cmp(int u,int v) {return A.In[u]<A.In[v];}
int sa[N],sb[N],st[N],tp;
ll ans=0;
void DP(int u) {
// printf("#%d %d\n",u,A.len[u]);
ans+=1ll*A.len[u]*(sa[u]*sb[u]);
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
DP(v);
ans+=A.len[u]*(1ll*sa[v]*sb[u]+1ll*sa[u]*sb[v]);
sa[u]+=sa[v],sb[u]+=sb[v];
}
}
bool mark[N];
int main() {
int n,q;scanf("%d%d",&n,&q);
scanf("%s",s);
for(int i=n-1;i>=0;i--)pos[i+1]=A.Insert(s[i]-'a');
lg[1]=0;for(int i=2;i<=(n<<1);i++)lg[i]=lg[i>>1]+1;
A.bd_Fail();
while(q--) {
int ca,cb,up=0;
scanf("%d%d",&ca,&cb);
for(int i=1;i<=ca;i++) {scanf("%d",&a[i]);d[++up]=a[i]=pos[a[i]];mark[a[i]]=1;}
for(int i=1;i<=cb;i++) {scanf("%d",&b[i]);b[i]=pos[b[i]];if(!mark[b[i]])d[++up]=b[i],mark[b[i]]=1;}
sort(d+1,d+1+up,cmp);
for(int i=1,sz=up;i<sz;i++) {
d[++up]=A.Lca(d[i],d[i+1]);
if(mark[d[up]])up--;else mark[d[up]]=1;
}
sort(d+1,d+1+up,cmp);
// puts("");for(int i=1;i<=up;i++) printf("%d ",d[i]);puts("");
st[++tp]=d[1];
for(int i=2;i<=up;i++) {
int u=A.In[d[i]];
while(tp&&(u<A.In[st[tp]]||u>A.Out[st[tp]]))tp--;
if(tp)add_edge(st[tp],d[i]);
// printf("!%d %d\n",st[tp],d[i]);
st[++tp]=d[i];
}
for(int i=1;i<=ca;i++)sa[a[i]]=1;
for(int i=1;i<=cb;i++)sb[b[i]]=1;
DP(d[1]);
printf("%lld\n",ans);
tp=ecnt=ans=0;for(int i=1;i<=up;i++)mark[d[i]]=sa[d[i]]=sb[d[i]]=head[d[i]]=0;
}
return 0;
}

[CF1073G]LCP问题的更多相关文章

  1. CF1073G Yet Another LCP Problem

    题目传送门. 题意简述:给出 \(s\),多次询问给出长度分别为 \(k,l\) 的序列 \(a,b\),求 \(\sum_{i=1}^k\sum_{j=1}^l\mathrm{LCP}(s[a_i: ...

  2. cf1073G Yet Another LCP Problem (SA+权值线段树)

    反正先求一遍sa 然后这个问题可以稍微转化一下 默认比较A.B数组中元素的大小都是比较它们rank的大小,毕竟两个位置的LCP就是它们rank的rmq 然后每次只要求B[j]>=A[i]的LCP ...

  3. CF1073G Yet Another LCP Problem 后缀自动机 + 虚树 + 树形DP

    题目描述 记 $lcp(i,j)$ 表示 $i$ 表示 $i$ 这个后缀和 $j$ 这个后缀的最长公共后缀长度给定一个字符串,每次询问的时候给出两个正整数集合 $A$ 和 $B$,求$\sum_{i\ ...

  4. 【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014 题意:支持插入一个字符.修改一个字符,查询lcp.(总长度<=100000, 操作< ...

  5. poj 2774 Long Long Message 后缀数组LCP理解

    题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #inclu ...

  6. hdu 3518 Boring counting 后缀数组LCP

    题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output ...

  7. BZOJ2105: 增强型LCP

    2105: 增强型LCP Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 366  Solved: 86[Submit][Status] Descrip ...

  8. LCP Array(思维)

    LCP Array Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Tota ...

  9. hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq

    http://acm.hdu.edu.cn/showproblem.php? pid=4691 去年夏天,更多的学校的种族称号.当时,没有后缀数组 今天将是,事实上,自己的后缀阵列组合rmq或到,但是 ...

随机推荐

  1. SSM实现个人博客-day01

    1.需求分析 项目源码免费下载:SSM实现个人博客 有问题请询问vx:kht808

  2. python函数基础算法简介

    一.多层语法糖本质 """ 语法糖会将紧挨着的被装饰对象名字当参数自动传入装饰器函数中""" def outter(func_name): ...

  3. Conda安装及第一个py程序

    Conda安装及第一个py程序 安装Conda 下载安装 在Anaconda官网下载Anaconda 打开Conda安装程序 设置好安装目录(这个一定要记好,后边要用),比如我的目录就是 D:\Pro ...

  4. OpenHarmony 3.1 Beta 版本关键特性解析——ArkUI canvas组件

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 江英杰 华为技术有限公司 canvas 是 ArkUI 开发框架里的画布组件,常用于自定义绘制图形.因为其轻量.灵活. ...

  5. Java语言学习day17--7月23日

    1.面向对象思想2.类与对象的关系3.局部变量和成员变量的关系4.封装思想5.private,this关键字6.随机点名器 ###01面向对象和面向过程的思想 * A: 面向过程与面向对象都是我们编程 ...

  6. OA办公软件篇(二)—权限管理

    权限管理的背景 权限管理的作用 迭代历程 关键名词释义 权限管理模型 具体实现 写在最后   权限管理的背景 在OA办公软件篇(一)-组织架构一文中,我们说到组织架构是软件系统的权限体系的重要搭建依据 ...

  7. Math内置对象 常用的方法

    属性: Math.Pi 方法: Math.max()   最大值 Math.min()  最小值 Math.ceil()  向上取整 Math.floor() 向下取整 Math.random()   ...

  8. Photoshop图片处理在线网页使用无需下载绿色

    今天给大家推荐一个ps在线版网页 实测使用效果不错,绿色简介,无需下载,不卡顿一般的电脑配置都可以带起来 因为是在线的所以是精简版的,但是一般ps软件有的工具,功能他都有,比较适合及时性使用 废话不多 ...

  9. selenium模块跳过用户名密码验证码输入,加载浏览器标签和cookie,进行翻页爬虫多页动态加载的数据(js)

    能解决登陆一次后,之后不需要二次登陆的动态加载数据,网页保存的cookie和标签,加入到selenium自动化测试浏览器中 1 from selenium import webdriver 2 imp ...

  10. 技术分享 | Web自动化之Selenium安装

    Web 应用程序的验收测试常常涉及一些手工任务,例如打开一个浏览器,并执行一个测试用例中所描述的操作.但是手工执行的任务容易出现人为的错误,也比较费时间.因此,将这些任务自动化,就可以消除人为因素.S ...