CF666E 【Forensic Examination】

题目

每天一道\(SAM\)真是非常开心

一看就是广义\(SAM\)+线段树合并了

我们存好\(S\)串每一个前缀的终点,之后在\(parent\)树上倍增找到表示\(S[l,r]\)这个子串的节点,我们用线段树合并维护好\(endpos\)集合,查一个区间最大值就好了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 2000005
#define M 10000005
#define re register
#define LL long long
#define mp std::make_pair
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
typedef std::pair<int,int> pii;
struct E{int v,nxt;}e[maxn];
char S[maxn];
int len[maxn],fa[maxn],son[maxn][26],endpos[maxn],to[maxn],head[maxn],rt[maxn];
int f[maxn][22],deep[maxn],loog[maxn];
int n,m,Q,__,num,lst=1,cnt=1,tot;
int l[M],r[M],sum[M],d[M];
inline void add(int x,int y){e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
inline void pushup(int x) {
    if(sum[l[x]]>=sum[r[x]]) sum[x]=sum[l[x]],d[x]=d[l[x]];
        else sum[x]=sum[r[x]],d[x]=d[r[x]];
}
int change(int now,int x,int y,int pos) {
    if(!now) now=++tot;
    if(x==y) {sum[now]++;d[now]=x;return now;}
    int mid=x+y>>1;
    if(pos<=mid) l[now]=change(l[now],x,mid,pos);
        else r[now]=change(r[now],mid+1,y,pos);
    pushup(now);
    return now;
}
int merge(int a,int b,int x,int y)  {
    if(!a) return b;if(!b) return a;
    int root=++tot;
    if(x==y) {sum[root]=sum[a]+sum[b],d[root]=x;return root;}
    int mid=x+y>>1;
    l[root]=merge(l[a],l[b],x,mid),r[root]=merge(r[a],r[b],mid+1,y);
    pushup(root);
    return root;
}
inline void ins(int c,int o)    {
    int p=++cnt,f=lst; lst=p;
    len[p]=len[f]+1;
    if(!o) to[++__]=p;
        else rt[p]=change(rt[p],1,m,o);
    while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    if(!f) {fa[p]=1;return;}
    int x=son[f][c];
    if(len[f]+1==len[x]) {fa[p]=x;return;}
    int y=++cnt;
    len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
}
void dfs(int x) {
    for(re int i=head[x];i;i=e[i].nxt)
        deep[e[i].v]=deep[x]+1,dfs(e[i].v),rt[x]=merge(rt[x],rt[e[i].v],1,m);
}
pii query(int now,int x,int y,int lx,int ry)
{
    if(lx<=x&&ry>=y) return mp(sum[now],d[now]);
    int mid=x+y>>1;
    if(ry<=mid) return query(l[now],x,mid,lx,ry);
    if(lx>mid) return query(r[now],mid+1,y,lx,ry);
    pii a=query(l[now],x,mid,lx,ry),b=query(r[now],mid+1,y,lx,ry);
    if(a.first>=b.first) return a; return b;
}
int main()
{
    scanf("%s",S+1);n=strlen(S+1);
    for(re int i=1;i<=n;i++) ins(S[i]-‘a‘,0);
    scanf("%d",&m);
    for(re int i=1;i<=m;i++)
    {
        scanf("%s",S+1);n=strlen(S+1);lst=1;
        for(re int j=1;j<=n;j++) ins(S[j]-‘a‘,i);
    }
    for(re int i=2;i<=cnt;i++) add(fa[i],i);
    deep[1]=1,dfs(1);
    for(re int i=1;i<=cnt;i++) f[i][0]=fa[i];
    for(re int i=2;i<=cnt;i++) loog[i]=loog[i>>1]+1;
    for(re int j=1;j<=loog[cnt];j++)
        for(re int i=1;i<=cnt;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    scanf("%d",&Q);
    int x,y,L,R;
    while(Q--)
    {
        scanf("%d%d%d%d",&x,&y,&L,&R);
        int Len=R-L+1;
        int now=to[R];
        for(re int i=loog[deep[now]];i>=0;--i)
        if(f[now][i]&&len[f[now][i]]>=Len) now=f[now][i];
        pii ans=query(rt[now],1,m,x,y);
        if(ans.first) printf("%d %d\n",ans.second,ans.first);
            else printf("%d ",x),puts("0");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/asuldb/p/10289797.html

时间: 2024-10-15 22:55:34

CF666E 【Forensic Examination】的相关文章

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

【c/c++】内存分配大小

测试平台:linux 32位系统 用sizeof()运算符计算分配空间大小.单位:字节 1. 数组名与变量名的区别 int main() { char q[] = "hello"; cout << "q:" << sizeof(q) << endl; char *mq = q; cout << "mq:" << sizeof(mq) << endl; const char *

【 js 基础 】Javascript “继承”

是时候写一写 "继承"了,为什么加引号,因为当你阅读完这篇文章,你会知道,说是 继承 其实是不准确的. 一.类1.传统的面向类的语言中的类:类/继承 描述了一种代码的组织结构形式.举个例子:"汽车"可以被看作是"交通工具"的一种特例.我们可以定义一个 Vehicle 类和一个 Car 类来对这种关系进行描述.Vehicle 的定义可能包含引擎.载人能力等,也就是 所有交通工具,比如飞机.火车和汽车等都有的通用的功能描述.在对 Car 类进行定义的

服务 Service【经典案例】

2017-1-19 Activity public class MainActivity extends ListActivity {     private boolean flag;//线程结束条件     public static final String ACTION_TEST_SERVICE = "com.bqt.service.TEST_SERVICE";     private MyServiceConnection conn;     private IBinderI

【N版】openstack——走进云计算(一)

[N版]openstack--走进云计算 一.云计算 云计算是一种按使用量付费的模式,这种模式提供可用的.便捷的.按需的网络访问,进入可配置的计算资源共享池(资源包括:网络.服务器.存储.应用软件.服务),这些资源能够被快速提供,只需投入很少的管理工作,或与服务供应商进行很少的交互. 1.1云计算的特点和优势 1)云计算是一种使用模式 2)云计算必须通过网络访问 3)弹性计算,按需付费 1.2在云计算之前的模式或技术 1)IDC托管 2)IDC租用 3)虚拟主机(卖空间的) 4)VPS:虚拟专用

【N版】openstack——认证服务keystone(三)

[N版]openstack--认证服务keystone 一.keystone介绍 1.1keystone Keystone(OpenStack Identity Service)是 OpenStack 框架中负责管理身份验证.服务规则和服务令牌功能的模块.用户访问资源需要验证用户的身份与权限,服务执行操作也需要进行权限检测,这些都需要通过 Keystone 来处理. 用户认证:用户权限与用户行为跟踪 服务目录:提供一个服务目录,包括所有服务项与相关API的端点 主要涉及如下概念: User:  

【N版】openstack——镜像服务glance(四)

[N版]openstack--镜像服务glance 一.openstack之glance镜像服务 1.1glance介绍 glance主要是由三部分组成 glance-api:接收云系统镜像的创建,删除,读取请求,类似nova-api,通过其他模块(glance-registry及image store)来完成诸如镜像的查找.获取.上传.删除等操作,api监听端口9292. glance-registry:云系统的镜像注册服务,用于与mysql数据库交互,存储或获取镜像的元数据(metadata

Python之路【第十七篇】:Django【进阶篇 】

Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')

Python之路【第九篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度.Memcached基于一个存储键/值对的hashmap.其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信. Memc