zoukankan      html  css  js  c++  java
  • 【LOJ#6041】事情的相似度

    题面

    https://loj.ac/problem/6041

    题解

    两个后缀的$LCS$,就是在后缀树上的$LCA$的深度。对于同属于一个$LCA$的点,我们只需要在原序列上连续的两个(实现上,直接在插进去的时候找就可以了,要是遍历一遍复杂度就假了)

    启发式合并。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<algorithm>
    #include<vector>
    #define ri register int
    #define N 100500
    using namespace std;
    
    int n,q,cc,ans[N];
    char s[N];
    
    struct ques {
      int l,r,id;
      bool operator < (const ques &rhs) const {
        return r<rhs.r || (r==rhs.r && l<rhs.l);
      }
    } qu[N];
    
    struct pir{
      int l,r,v;
      bool operator < (const pir &rhs) const {
        return r<rhs.r || (r==rhs.r && l<rhs.l);
      }
    } pp[N<<5];
    
    struct SAM{
      int ch[N<<1][2];
      int ff[N<<1],len[N<<1];
      int las,tot;
      vector<int> son[N<<1];
      set<int> endp[N<<1];
      void clear() {
        las=tot=1;
      }
      void extend(int c){
        int p=las,np=++tot; las=tot;
        len[np]=len[p]+1;
        while (p && ch[p][c]==0) ch[p][c]=np,p=ff[p];
        if (!p) {
          ff[np]=1;
        }
        else {
          int q=ch[p][c];
          if (len[q]==len[p]+1) {
            ff[np]=q;
          }
          else {
            int nq=++tot;
            len[nq]=len[p]+1; ff[nq]=ff[q];
            for (ri i=0;i<2;i++) ch[nq][i]=ch[q][i];
            ff[np]=ff[q]=nq;
            while (p && ch[p][c]==q) ch[p][c]=nq,p=ff[p];
          }
        }
        endp[np].insert(len[np]);
      }
      
      void maketree() {
        for (ri i=1;i<=tot;i++) son[ff[i]].push_back(i);
      }
      void merge(int x) {
        set<int> :: iterator it,it2,itp,itq;
        for (ri i=0;i<son[x].size();i++) {
          merge(son[x][i]);
          if (endp[x].size()<endp[son[x][i]].size()) swap(endp[x],endp[son[x][i]]);
          for (it=endp[son[x][i]].begin();it!=endp[son[x][i]].end();++it) {
            endp[x].insert(*it);
            it2=endp[x].lower_bound(*it);
            itq=itp=it2;
            if (itp!=endp[x].begin()) {
              --itp;
              pp[++cc]=(pir){*itp,*it,len[x]};
            }
            {
              itq++;
              if (itq!=endp[x].end()) pp[++cc]=(pir){*it,*itq,len[x]};
            }
            endp[x].erase(*it);
          }
          for (it=endp[son[x][i]].begin();it!=endp[son[x][i]].end();++it) endp[x].insert(*it);
        }
      }
    } sam;
    
    struct Fenwick{
      int a[N];
      void insert(int loc,int v) {
        loc=n-loc+1;
        for (ri i=loc;i<=n;i+=(i&(-i))) a[i]=max(a[i],v);
      }
      int find(int loc) {
        loc=n-loc+1;
        int ans=0;
        for (ri i=loc;i;i-=(i&(-i))) ans=max(ans,a[i]);
        return ans;
      }
    } fg;
    
    int main(){
      scanf("%d %d",&n,&q);
      sam.clear();
      scanf("%s",s+1);
      int l=strlen(s+1);
      for (ri i=1;i<=l;i++) sam.extend(s[i]-'0');
      for (ri i=1;i<=q;i++) {
        scanf("%d %d",&qu[i].l,&qu[i].r);
        qu[i].id=i;
      }
      sam.maketree();
      cc=0; sam.merge(1);
      sort(qu+1,qu+q+1);
      sort(pp+1,pp+cc+1);
      int p=1;
      for (ri i=1;i<=q;i++) {
        while (pp[p].r<=qu[i].r && p<=cc) fg.insert(pp[p].l,pp[p].v),p++;
        ans[qu[i].id]=fg.find(qu[i].l);
      }
      for (ri i=1;i<=q;i++) printf("%d
    ",ans[i]);
      return 0;
    }
  • 相关阅读:
    程序猿初出茅庐之一:学习方法
    Winform实现鼠标可穿透的窗体镂空效果
    HashMap源码分析(上)
    Java Integer常量池——IntegerCache内部类
    find the Nth highest salary(寻找第N高薪水)
    分布式理论:深入浅出Paxos算法
    smash:一个类unix内核
    【官网翻译】如何在VSCode中使用代码片段功能(snippets)?
    JavaScript与魔数检测
    给你一个团队,你能怎么管-读后感-凝聚力和执行力(1)
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11279340.html
Copyright © 2011-2022 走看看