• 【CF666E】Forensic Examination


    广义SAM专题的最后一题了……呼

    题意:

    给出一个长度为$n$的串$S$和$m$个串$T_{1cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[plcdots pr]$在$T_lcdots T_r$中哪个串出现次数最多,出现了多少次。

    $1leq n,qleq 10^5,1leq m,sum|T|leq 10^4$

    串中只会出现小写字母

    题解:

    神题啊……放图镇楼

    先对T串建出广义SAM,然后把S放到上面匹配,求出每个字符所代表的节点,那么每次查询就相当于求这一段字符在SAM上对应的节点的right集合包含的字符串的众数是哪个串,显然这是parent树上的一个子树众数问题;

    考虑如何维护right集合在所有$T$中的出现次数,可以对每一个节点开一棵线段树,维护每个T串的出现次数的最大值,这样子在parent树上从下往上线段树合并即可求出right集合;

    把询问离线按照右端点排序,把询问标记打在parent树上,最后dfs一遍合并+处理询问即可;

    口胡起来不难但是写起来……超爽!

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<vector>
      6 #include<cmath>
      7 #include<queue>
      8 #define inf 2147483647
      9 #define eps 1e-9
     10 using namespace std;
     11 typedef long long ll;
     12 typedef double db;
     13 struct task{
     14     int v,id;
     15     task(){v=id=0;}
     16     friend bool operator <(task a,task b){
     17         return a.v==b.v?a.id>b.id:a.v<b.v;
     18     }
     19 }ans[500001];
     20 struct qu{
     21     int l,r,ql,qr;
     22 }q[500001];
     23 struct edge{
     24     int v,next;
     25 }a[1000001];
     26 struct node{
     27     int ls,rs;
     28     task v;
     29 }t[4000001];
     30 int n,m,Q,len,ch,nw=1,tote=0,tot=1,rt=1,cnt=0,last,head[1000001],rts[1000001],son[1000001][26],fa[1000001],mx[1000001],f[1000001][20];
     31 vector<int>qrs[500001];
     32 vector<int>as[500001];
     33 char st[500001],tt[500001];
     34 void add(int u,int v){
     35     a[++tote].v=v;
     36     a[tote].next=head[u];
     37     head[u]=tote;
     38 }
     39 void updata(int &u,int l,int r,int x){
     40     if(!u)u=++cnt;
     41     if(l==r){
     42         t[u].v.v++;
     43         t[u].v.id=x;
     44         return;
     45     }
     46     int mid=(l+r)/2;
     47     if(x<=mid)updata(t[u].ls,l,mid,x);
     48     else updata(t[u].rs,mid+1,r,x);
     49     t[u].v=max(t[t[u].ls].v,t[t[u].rs].v);
     50 }
     51 void merge(int &x,int y){
     52     if(!x||!y){
     53         x|=y;
     54         return;
     55     }
     56     if(!t[x].ls&&!t[x].rs){
     57         t[x].v.v+=t[y].v.v;
     58         return;
     59     }
     60     merge(t[x].ls,t[y].ls);
     61     merge(t[x].rs,t[y].rs);
     62     t[x].v=max(t[t[x].ls].v,t[t[x].rs].v);
     63 }
     64 task query(int u,int l,int r,int L,int R){
     65     if(L<=l&&r<=R){
     66         return t[u].v;
     67     }
     68     int mid=(l+r)/2;
     69     task ret;
     70     if(L<=mid)ret=max(ret,query(t[u].ls,l,mid,L,R));
     71     if(mid<R)ret=max(ret,query(t[u].rs,mid+1,r,L,R));
     72     return ret;
     73 }
     74 void extend(int ch){
     75     int p=last,np=++tot;
     76     mx[np]=mx[p]+1;
     77     for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
     78     if(!p)fa[np]=rt;
     79     else{
     80         int q=son[p][ch];
     81         if(mx[q]==mx[p]+1)fa[np]=q;
     82         else{
     83             int nq=++tot;
     84             mx[nq]=mx[p]+1;
     85             memcpy(son[nq],son[q],sizeof(son[q]));
     86             fa[nq]=fa[q];
     87             fa[q]=fa[np]=nq;
     88             for(;p&&son[p][ch]==q;p=fa[p])son[p][ch]=nq;
     89         }
     90     }
     91     last=np;
     92 }
     93 void dfs(int u){
     94     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     95         int v=a[tmp].v;
     96         dfs(v);
     97         merge(rts[u],rts[v]);
     98     }
     99     for(int i=0,ii=as[u].size();i<ii;i++){
    100         ans[as[u][i]]=query(rts[u],1,m,q[as[u][i]].l,q[as[u][i]].r);
    101     }
    102 }
    103 int main(){
    104     memset(head,-1,sizeof(head));
    105     scanf("%s%d",st+1,&m);
    106     n=strlen(st+1);
    107     for(int i=1;i<=m;i++){
    108         scanf("%s",tt);
    109         len=strlen(tt);
    110         last=rt;
    111         for(int j=0;j<len;j++){
    112             extend(tt[j]-'a');
    113             updata(rts[last],1,m,i);
    114         }
    115     }
    116     scanf("%d",&Q);
    117     for(int i=1;i<=Q;i++){
    118         scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].ql,&q[i].qr);
    119         qrs[q[i].qr].push_back(i);
    120     }
    121     for(int i=2;i<=tot;i++){
    122         f[i][0]=fa[i];
    123         add(fa[i],i);
    124     }
    125     for(int j=1;j<=19;j++){
    126         for(int i=1;i<=tot;i++){
    127             f[i][j]=f[f[i][j-1]][j-1];
    128         }
    129     }
    130     len=0;
    131     for(int i=1;i<=n;i++){
    132         ch=st[i]-'a';
    133         for(;nw&&!son[nw][ch];)nw=fa[nw],len=mx[nw];
    134         if(!nw){
    135             nw=rt;
    136             len=0;
    137         }else{
    138             nw=son[nw][ch];
    139             len++;
    140             for(int j=0,jj=qrs[i].size();j<jj;j++){
    141                 int v=qrs[i][j];
    142                 if(len>=q[v].qr-q[v].ql+1){
    143                     int _nw=nw;
    144                     for(int k=19;k>=0;k--){
    145                         if(mx[f[_nw][k]]>=q[v].qr-q[v].ql+1){
    146                             _nw=f[_nw][k];
    147                         }
    148                     }
    149                     as[_nw].push_back(v);
    150                 }
    151             }
    152         }
    153     }
    154     dfs(1);
    155     for(int i=1;i<=Q;i++){
    156         if(!ans[i].v)ans[i].id=q[i].l;
    157         printf("%d %d
    ",ans[i].id,ans[i].v);
    158     }
    159     return 0;
    160 }
  • 相关阅读:
    使用CodeQL寻找SSTI漏洞
    thinkphp3缓存漏洞
    SecCrawler windows配置
    了解ThinkPHP
    Mybaitsplus 开启SQL日志的两种方式
    找不对自定义typeHandler:java.lang.IllegalStateException: No typehandler found for mapping ...
    Windows编程系列:如何监测某个进程是否退出?
    什么时候在C#中使用结构体?
    解决git在push时,报git authentication failed的问题
    Deep3DFaceRecon_pytorch 运行错误
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/10160391.html
Copyright © 2020-2023  润新知