Codeforces 666E Forensic Examination SAM+权值线段树

第一次做这种$SAM$带权值线段树合并的题 然而$zjq$神犇看完题一顿狂码就做出来了 $Orz$

首先把所有串当成一个串建$SAM$ 我们对$SAM$上每个点 建一棵权值线段树 每个叶子节点表示一个匹配串能到达这个点的子串个数 这样我们对最后的$SAM$的权值线段树按$parent$树合并 询问的时候找到对应的$SAM$上的权值线段树直接查询就好了

具体的操作看代码吧~

#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 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=1230010;
/*
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;
}
pa operator * (const pa&A,const pa&B){return A.fi==B.fi?(A.se<B.se?A:B):(A.fi>B.fi?A:B);}
pa operator + (const pa&A,const pa&B){return mk(A.fi+B.fi,A.se);}
pa t[N*23];
char s[N];
int n,m,Q,c[N][27],par[N],len[N],fa[N][21],ls[N*23],rs[N*23],h[N],rt=1,sz=1,last=1,root[N],w[N],b[N],id;
void extend(int x){
    int np=++sz,p=last;
    len[np]=len[p]+1,last=np;
    for(;p&&!c[p][x];p=par[p]) c[p][x]=np;
    if(!p) par[np]=rt;
    else{
        int q=c[p][x];
        if(len[p]+1==len[q]) par[np]=q;
        else{
            int nq=++sz;
            len[nq]=len[p]+1,par[nq]=par[q],par[q]=par[np]=nq;
            memcpy(c[nq],c[q],sizeof c[nq]);
            for(;p&&c[p][x]==q;p=par[p]) c[p][x]=nq;
        }
    }
}
void modify(int&pos,int l,int r,int x){
    if(!pos) pos=++id;
    if(l==r){
        t[pos].fi++,t[pos].se=l;
//      cout<<t[pos].fi<<" "<<t[pos].se<<endl;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid) modify(ls[pos],l,mid,x);
    else modify(rs[pos],mid+1,r,x);
    t[pos]=t[ls[pos]]*t[rs[pos]];
}
inline int merge(int x,int y,int l,int r)
{
    if (!x||!y) return x|y;
    int z=++id;
    if (l==r) {
        t[z]=t[x]+t[y];
        return z;
    }
    int mid=(l+r)>>1;
    ls[z]=merge(ls[x],ls[y],l,mid),rs[z]=merge(rs[x],rs[y],mid+1,r);
    t[z]=t[ls[z]]*t[rs[z]];
    return z;
}
pa Query(int pos,int l,int r,int nl,int nr){
    if(!pos) return mk(0,0);
    if(nl<=l&&r<=nr) return t[pos];
    int mid=l+r>>1;
    if(nr<=mid) return Query(ls[pos],l,mid,nl,nr);
    else if(nl>mid) return Query(rs[pos],mid+1,r,nl,nr);
    else return Query(ls[pos],l,mid,nl,nr)*Query(rs[pos],mid+1,r,nl,nr);
}
void topsort(){
    for(int i=1;i<=sz;i++) w[len[i]]++;
    for(int i=1;i<=sz;i++) w[i]+=w[i-1];
    for(int i=1;i<=sz;i++) b[w[len[i]]--]=i;
    for(int i=sz;i;i--){
        int j=b[i];
        if(par[j]) root[par[j]]=merge(root[par[j]],root[j],1,n);
    }
}
void get_fa(){
    for(int i=1;i<=sz;i++) fa[i][0]=par[i];
    for(int i=1;i<=20;i++) for(int j=1;j<=sz;j++) fa[j][i]=fa[fa[j][i-1]][i-1];
}
int get(int l,int r){
    int L=r-l+1,x=h[r];
    for(int i=20;~i;i--) if(len[fa[x][i]]>=L) x=fa[x][i];
//  -len[par[x]]-len[par[fa[x][i]]]
    return x;
}
int main(){
#ifdef Devil_Gary
    freopen("in.txt","r",stdin);
#endif
    scanf("%s",s+1),m=strlen(s+1);
    for(int i=1;i<=m;i++) extend(s[i]-'a'),h[i]=last;
    n=read();
    for(int i=1;i<=n;i++){
        scanf("%s",s+1),m=strlen(s+1),extend(26);
        for(int j=1;j<=m;j++) extend(s[j]-'a'),modify(root[last],1,n,i);
    }
//  bug(sz);
    topsort(),get_fa();
    for(Q=read();Q;Q--){
        int l=read(),r=read(),pl=read(),pr=read(),x=get(pl,pr);
        pa ans=Query(root[x],1,n,l,r);
        if(!ans.fi) printf("%d 0\n",l);
        else printf("%d %d\n",ans.se,ans.fi);
    }
}

原文地址:https://www.cnblogs.com/devil-gary/p/9057102.html

时间: 2024-08-02 11:11:03

Codeforces 666E Forensic Examination SAM+权值线段树的相关文章

CF666E Forensic Examination SAM+倍增,线段树和并

题面: 给你一个串S以及一个字符串数组T[1..m],q次询问,每次问S的子串S[p_l..p_r]在T[l..r]中的哪个串里的出现次数最多,并输出出现次数.如有多解输出最靠前的那一个. 分析: 第一次见这道题时,由于对算法十分陌生,就将其压进了任务计划,这一天又提到了这道题,这才算是重见天日. 数据结构题,越来越注重多种数据结构的搭配使用.搭配使用呢,我们就要知道各种数据结构的功能与适用范围,下面是这道题一个理想的思考过程(虽然我是抄的题解--) 首先,一个模式串的区间要在多个串上进行匹配,

CF.666E.Forensic Examination(广义后缀自动机 线段树合并)

题目链接 \(Description\) 给定串S和m个串Ti.Q次询问,每次询问l,r,pl,pr,求S[pl~pr]在Tl~Tr中的哪个串出现次数最多,输出最多次数及其T的下标.若有多个,输出下标最小的. \(Solution\) 挺好的题吧 对T个串建SAM,然后要求出SAM每个节点上|right|最大的是哪个串. 每个节点的|right|可以在DFS parent树时合并子节点得到,如果用线段树维护,|right|最大的位置也可以合并得到. 这样可以离线处理询问,最后DFS一遍得到答案.

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

P2234 [HNOI2002]营业额统计 (权值线段树)

P2234 [HNOI2002]营业额统计 题目描述 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定义了一种最小波动值来衡量这种情况: 当最小波动值越大

【BZOJ4605】崂山白花蛇草水 权值线段树+kd-tree

[BZOJ4605]崂山白花蛇草水 Description 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob特地为他准备了999,999,999,999,999,999瓶崂山白花蛇草水,想要灌神犇Aleph.神犇Aleph求(跪着的)蒟蒻Bob不要灌他,由于神犇Aleph是神犇,蒟蒻Bob最终答应了他的请求,但蒟蒻Bob决定将计就计,也让神犇Aleph回答

【bzoj2161】布娃娃 权值线段树

题目描述 小时候的雨荨非常听话,是父母眼中的好孩子.在学校是老师的左右手,同学的好榜样.后来她成为艾利斯顿第二代考神,这和小时候培养的良好素质是分不开的.雨荨的妈妈也为有这么一个懂事的女儿感到高兴.一次期末考试,雨荨不知道第多少次,再次考了全年级第一名.雨荨的妈妈看到女儿100分的成绩单时,脸上又泛起了幸福的笑容,作为奖励,她给雨荨买了n个布娃娃.细心的雨荨发现,第i个布娃娃有一个耐心值P[i]以及一个魅力值C[i],并且还有能够忍受的耐心值的上限R[i]以及下限L[i].当一个布娃娃j满足L[

模板——权值线段树(逆序对)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 62455   Accepted: 23259 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree

题目描述 神犇Aleph在SDOI Round2前立了一个flag:如果进了省队,就现场直播喝崂山白花蛇草水.凭借着神犇Aleph的实力,他轻松地进了山东省省队,现在便是他履行诺言的时候了.蒟蒻Bob特地为他准备了999,999,999,999,999,999瓶崂山白花蛇草水,想要灌神犇Aleph.神犇Aleph求(跪着的)蒟蒻Bob不要灌他,由于神犇Aleph是神犇,蒟蒻Bob最终答应了他的请求,但蒟蒻Bob决定将计就计,也让神犇Aleph回答一些问题.具体说来,蒟蒻Bob会在一个宽敞的广场上

【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少.这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问.这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少.这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问.(orz 主席