• P4094 [HEOI2016/TJOI2016]字符串(二分+多种数据结构)


    P4094 [HEOI2016/TJOI2016]字符串(二分+多种数据结构)

    在洛谷写的第一道黑题留念。第一次一遍默写对了那么多数据结构的板子,嘻嘻。
    问题是这样的:每次询问max{字符串S的某一子串A的所有子串和另一子串B的lcp}

    如果暴力枚举A的子串那一定是会超时的

    这里注意到如果x是满足条件的答案,那么比x小的数也能够满足条件,因此答案满足单调性,可以将问题转换为判断一个值是否能满足条件

    首先x不能超过min{len(A的子串),len(B)},由于B是定的,我们可以用rk数组找到B在所有后缀中的位置,这里又注意到其他后缀与B的lcp也符合单调性质,B往上往下的后缀与B的lcp递减,此时可以从B的位置向两边二分出满足条件的最小lcp的位置的L和R,此时只要判断这个区间内是否含有在子串A[l,r]的子串[l,r-x+1]中的后缀,需要快速做出这个判断,可以对sa数组建立可持久化权值线段树,每次二分x时查询L到R版本之间是否存在满足条件的后缀。

    复杂度是倍增算sa的nlogn+询问数m×第一个二分的logn×第二个二分+主席树的logn也就是(O(nlogn+mlog^2n))

    const int N = 2e5+10;
    int n, m, q;
    
    struct seg{
      int l, r, val;
    }node[N*40];
    int root[N];
    char s[N];
    int sa[N], x[N], y[N], c[N], rk[N], height[N];
    
    int LOG[N] = {0, 0, 1};
    int st[N][22];
    
    void get_sa() {
      rep(i,1,n) c[x[i]=s[i]]++;
      rep(i,2,m) c[i] += c[i-1];
      per(i,n,1) sa[c[x[i]]--] = i;
      for (int k = 1; k <= n; k <<= 1) {
        int num = 0;
        rep(i,n-k+1,n) y[++num] = i;
        rep(i,1,n) if (sa[i] > k) y[++num] = sa[i] - k;
        rep(i,1,m) c[i] = 0;
        rep(i,1,n) c[x[i]]++;
        rep(i,2,m) c[i] += c[i-1];
        per(i,n,1) sa[c[x[y[i]]]--] = y[i];
        swap(x,y);
        x[sa[1]] = 1, num = 1;
        rep(i,2,n) x[sa[i]] = (y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]) ? num : ++num;
        if (num == n) break;
        m = num;
      }
    }
    
    void get_height() {
      rep(i,1,n) rk[sa[i]] = i;
      for (int i = 1, k = 0; i <= n; i++) {
        if (rk[i] == 1) continue;
        if (k) --k;
        int j = sa[rk[i]-1];
        while (i + k <= n && j + k <= n && s[i+k] == s[j+k]) ++k;
        height[rk[i]] = k;
      }
    }
    
    void get_st() {
      rep(i,1,n) st[i][0] = height[i];
      rep(j,1,LOG[n]) {
        for (int i = 1; i + (1ll<<j) - 1 <= n; i++) {
          st[i][j] = min(st[i][j-1], st[i+(1ll<<(j-1))][j-1]);
        }
      }
    }
    
    int rmq(int l, int r) {
      int len = r-l+1, x = LOG[len];
      return min(st[l][x], st[r-(1ll<<x)+1][x]);
    }
    
    int cnt;
    
    void ins(int l, int r, int pre, int &now, int p) {
      node[now=++cnt] = node[pre];
      node[now].val++;
      if (l == r) return;
      int mid = l + r >> 1;
      if (p <= mid) ins(l, mid, node[pre].l, node[now].l, p);
      else ins(mid+1, r, node[pre].r, node[now].r, p);
    }
    
    int query(int l, int r, int ll, int rr, int L, int R) {
      if (ll <= l && rr >= r) return node[R].val - node[L].val;
      int mid = l + r >> 1;
      int res = 0;
      if (ll <= mid) res += query(l, mid, ll, rr, node[L].l, node[R].l);
      if (rr > mid) res += query(mid+1, r, ll, rr, node[L].r, node[R].r);
      return res;
    }
    
    bool check(int x, int a, int b, int c) {
      int MID = rk[c], l, r, L = MID, R = MID;
      l = 1, r = MID;
      while (l <= r) {
        int mid = l + r >> 1;
        if (rmq(mid+1,MID) >= x) L = mid, r = mid - 1;
        else l = mid + 1; 
      }
      l = MID+1, r = n;
      while (l <= r) {
        int mid = l + r >> 1;
        if (rmq(MID+1, mid) >= x) R = mid, l = mid + 1;
        else r = mid - 1;
      }
      return query(1, n, a, b-x+1, root[L-1], root[R]) > 0;
    }
    
    int solve(int a, int b, int c, int d) {
      int l = 0, r = min(b-a+1, d-c+1);
      while (l < r) {
        int mid = l + r + 1 >> 1;
        if (check(mid, a, b, c)) l = mid;
        else r = mid - 1;
      }
      return l;
    }
    
    void run() {
      n = rd(), q = rd(), m = 122;
      scanf("%s",s+1);
      get_sa();
      get_height();
      get_st();
      rep(i,1,n) ins(1,n,root[i-1],root[i],sa[i]);
      while (q--) {
        int a = rd(), b = rd(), c = rd(), d = rd();
        pnt(solve(a,b,c,d));
      }
    }
    
    signed main(){
      rep(i,3,N-1) LOG[i] = LOG[i>>1] + 1;
    //  for (tt = rd(); tt--; )
      run();
      return 0;
    }
    
  • 相关阅读:
    ssh实现免密码登录和文件传输
    linux后台执行程序相关命令
    orchestrator
    curl下载安装与使用
    goland使用
    mysql集群
    consul理解
    my.cnf
    数据库的表设计
    项目常见面试问题
  • 原文地址:https://www.cnblogs.com/hznudreamer/p/14067689.html
Copyright © 2020-2023  润新知