反正先求一遍sa

然后这个问题可以稍微转化一下

默认比较A、B数组中元素的大小都是比较它们rank的大小,毕竟两个位置的LCP就是它们rank的rmq

然后每次只要求B[j]>=A[i]的LCP(B[j],A[i]),然后再求A[j]>B[i]的LCP(A[j],B[i])即可

这两个其实是差不多的,下面只说B[j]>=A[i]的怎么算

排序以后从后往前推着做(当然从前往后也行)

用一个权值线段树记下来LCP(A[i],B[j])==x的B[j]的数量、以及这个数量*x的和

然后考虑怎么把它从A[i]转移到A[i-1]

其实就是对于每个j给LCP(A[i],B[j])和LCP(A[i-1],A[i])取个min,放到权值线段树上,就是把大于LCP(A[i-1],A[i])的都删掉,然后在LCP(A[i-1],A[i])处加上刚才删掉的个数

所以我推着做的时候,先来取个min,然后把新来的B[j]加到线段树里,每做一个A[i]统计一下线段树整体的和即可

 #include<bits/stdc++.h>
#define pa pair<int,int>
#define CLR(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=4e5+; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} int N,M,Q;
char s[maxn];
int sa[maxn],rnk[maxn],hei[maxn],rank1[maxn],tmp[maxn],cnt[maxn];
int st[maxn][]; inline void getsa(){
int i,j=,k;
for(i=;i<=N;i++) cnt[s[i]]=;
for(i=;i<=M;i++) cnt[i]+=cnt[i-];
for(i=N;i;i--) rnk[i]=cnt[s[i]]; for(k=;j!=N;k<<=){
memset(cnt,,sizeof(cnt));
for(i=;i<=N;i++) cnt[rnk[i+k>N?:i+k]]++;
for(i=;i<=M;i++) cnt[i]+=cnt[i-];
for(i=N;i;i--) tmp[cnt[rnk[i+k>N?:i+k]]--]=i;
memset(cnt,,sizeof(cnt));
for(i=;i<=N;i++) cnt[rnk[i]]++;
for(i=;i<=M;i++) cnt[i]+=cnt[i-];
for(i=N;i;i--) sa[cnt[rnk[tmp[i]]]--]=tmp[i];
memcpy(rank1,rnk,sizeof(rank1));
rnk[sa[]]=j=;
for(i=;i<=N;i++){
if(rank1[sa[i]]!=rank1[sa[i-]]||rank1[sa[i]+k>N?:sa[i]+k]!=rank1[sa[i-]+k>N?:sa[i-]+k]) j++;
rnk[sa[i]]=j;
}M=j;
}
for(i=;i<=N;i++) sa[rnk[i]]=i;
} inline void geth(){
for(int i=,j=;i<=N;i++){
if(rnk[i]==) continue;
if(j) j--;
int x=sa[rnk[i]-];
while(x+j<=N&&i+j<=N&&s[x+j]==s[i+j]) j++;
hei[rnk[i]]=j;
}
} inline void getst(){
for(int i=N;i;i--){
st[i][]=hei[i];
for(int j=;st[i+(<<(j-))][j-];j++){
st[i][j]=min(st[i][j-],st[i+(<<(j-))][j-]);
}
}
} inline int rmq(int l,int r){
if(l>r) return N-sa[r]+;
int x=log2(r-l+);
return min(st[l][x],st[r-(<<x)+][x]);
} ll sum[maxn<<],siz[maxn<<];
bool laz[maxn<<]; inline void update(int p){sum[p]=sum[p<<]+sum[p<<|],siz[p]=siz[p<<]+siz[p<<|];}
inline void pushdown(int p){
if(!laz[p]) return;
int a=p<<,b=p<<|;
sum[a]=siz[a]=,laz[a]=;
sum[b]=siz[b]=,laz[b]=;
laz[p]=;
}
int erase(int p,int l,int r,int x,int y){
if(x<=l&&r<=y){
int re=siz[p];
siz[p]=sum[p]=;laz[p]=;
pushdown(p);
return re;
}else{
pushdown(p);
int m=l+r>>,re=;
if(x<=m) re=erase(p<<,l,m,x,y);
if(y>=m+) re+=erase(p<<|,m+,r,x,y);
update(p);
return re;
}
}
void add(int p,int l,int r,int x,int y){
if(l==r){
siz[p]+=y,sum[p]+=1ll*y*l;
}else{
pushdown(p);
int m=l+r>>;
if(x<=m) add(p<<,l,m,x,y);
else add(p<<|,m+,r,x,y);
update(p);
}
} inline bool cmp(int a,int b){return rnk[a]<rnk[b];} int A[maxn],B[maxn];
ll solve(int k,int l){
sort(A+,A+k+,cmp);sort(B+,B+l+,cmp);
ll re=;
for(int i=k,j=l;i;i--){
if(i!=k){
int x=rmq(rnk[A[i]]+,rnk[A[i+]]),t=erase(,,N,x+,N);
add(,,N,x,t);
}
for(;rnk[B[j]]>=rnk[A[i]]&&j;j--)
add(,,N,rmq(rnk[A[i]]+,rnk[B[j]]),);
re+=sum[];
}
erase(,,N,,N);
for(int i=k,j=l;j;j--){
if(j!=l){
int x=rmq(rnk[B[j]]+,rnk[B[j+]]),t=erase(,,N,x+,N);
add(,,N,x,t);
}
for(;rnk[A[i]]>rnk[B[j]]&&i;i--)
add(,,N,rmq(rnk[B[j]]+,rnk[A[i]]),);
re+=sum[];
}
erase(,,N,,N);
return re;
} int main(){
//freopen(".in","r",stdin);
int i,j,k;
N=rd(),Q=rd();
scanf("%s",s+);
M=;
getsa();geth();getst();
for(i=;i<=Q;i++){
int a=rd(),b=rd();
for(j=;j<=a;j++)
A[j]=rd();
for(j=;j<=b;j++)
B[j]=rd();
printf("%I64d\n",solve(a,b));
}
return ;
}

cf1073G Yet Another LCP Problem (SA+权值线段树)的更多相关文章

  1. BZOJ4627 前缀和 + 权值线段树

    https://www.lydsy.com/JudgeOnline/problem.php?id=4627 题意:求序列中和在L到R之间的字串种数. 要求的是和的范围,我们可以考虑先求一个前缀和pre ...

  2. F - 回转寿司 (权值线段树)

    题目链接:https://cn.vjudge.net/contest/281960#problem/F 题目大意:中文题目 具体思路:权值线段树,我们每次寻找的是满足 (i<j)   L< ...

  3. BZOJ 4605 崂山白花蛇草水(权值线段树+KD树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4605 [题目大意] 操作 1 x y k 表示在点(x,y)上放置k个物品, 操作 2 ...

  4. HDU 6464 免费送气球 【权值线段树】(广东工业大学第十四届程序设计竞赛)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6464 免费送气球 Time Limit: 2000/1000 MS (Java/Others)    M ...

  5. hdu 5592 ZYB's Premutation (权值线段树)

    最近在线段树的世界里遨游,什么都能用线段树做,这不又一道权值线段树了么. ZYB's Premutation Time Limit: 2000/1000 MS (Java/Others)    Mem ...

  6. [bzoj 2733]启发式合并权值线段树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 平衡树待学习.从一个博客学到了合并权值线段树的姿势:http://blog.csdn ...

  7. HDU 6464 权值线段树 && HDU 6468 思维题

    免费送气球 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  8. D. Restore Permutation(权值线段树)

    D. Restore Permutation time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  9. HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)

    layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...

随机推荐

  1. PHP的内存回收(GC)

    php官方对gc的介绍:http://php.net/manual/zh/features.gc.php

  2. 【kindle笔记】之 《浪潮之巅》- 2018-1-

    <浪潮之巅> 这本书推荐自最爱的政治课老师. 政治课老师张巍老师.我会一直记得你的. 以这样的身份来到这个学校,他人的质疑,自己的忐忑,老板的不公.犹犹豫豫谨小慎微地前进. 第一次听到这样 ...

  3. 4 Past progressive VS simple past

    1 一般过去时用来谈论过去开始和结束的活动.过去进行时用来谈论过去正在进行或者发生的活动. Why were you at office so later yesterday? I was worki ...

  4. Azure系列2.1.14 —— CopyState

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  5. The New Villa

    题目:The New Villa 题目链接:http://poj.org/problem?id=1137 题目大意: 一个人买了一个别墅,里面有很多房间,特别的是这个别墅的房间里灯的开关是乱套的,也就 ...

  6. laravel 循环中子元素使用&符号嵌入到父级,经典版

    /**ajax 获取企业名称 * * @param Request $request * * @return \Illuminate\Http\JsonResponse * @author lxw * ...

  7. python中的 list (列表)append()方法 与extend()方法的用法 和 区别

    参考: https://www.cnblogs.com/xuchunlin/p/5479119.html

  8. python之路--内置模块02

    一. namedtuple 命名元组->类似创建了一个类 from collections import namedtuple # 类 p = namedtuple("Point&qu ...

  9. python数据结构与算法第八天【冒泡排序】

    1.排序算法的稳定性 稳定排序算法会让原本有相同键值的记录维持相对次序 例如:对以下元组按照元组的第一个元素升序排列,元组如下: (4,1) (3,1) (3,7) (5,6) 若要满足条件,则可能的 ...

  10. 四、K8S

    一.查看日志 journalctl -xeu kubelet