[十二省联考 2019] 字符串问题

[十二省联考 2019] 字符串问题

题意很唬人,实际上就是让你建出一个二分图模型,然后求点权和最大的路径,其中 \(B_i\) 要向所有满足 \(B_i\)\(A_j\) 的前缀的 \(A_j\) 连边。直接连边是 \(O(n^2)\) 的。考虑优化,不难想到 SA 的优良性质,即 \(B_i\) 能连边的 \(A_j\) 在 SA 中是一个区间,那么这个东西就考虑线段树优化建边,然而还有长度的限制,所以要把线段树改成主席树,一边按照长度依次加入 \(A\) 依次加入 \(B\) 连向 \(A\) 的边。点数和边数都是 \(O(n \log n)\) 的,所以总复杂度是 \(O(\sum n \log n)\)

挺容易想的,想练一下代码能力就写了。大概写了两个半小时过了。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

namespace IO {
#define isdigit(x) (x >= '0' && x <= '9')
template<typename T>
inline void read(T &x) {
  x = 0; char ch = getchar(); int f = 0;
  for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
  for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
  if(f) x = -x;
}
template<typename T, typename... Rest>
inline void read(T &x, Rest&... rest) {
  read(x), read(rest...);
}
template<typename T>
inline void write(T x) {
  if(x < 0) putchar('-'), x = -x;
  if(x > 9) write(x / 10);
  putchar(x % 10 + '0');
}
#undef isdigit
}
using namespace IO;

const int N = 2e5 + 10;

char s[N];
int n, na, nb, m;

namespace Graph {
  vector<int> G[N * 40];
  int w[N * 40], d[N * 40], vis[N * 40], n;
  LL f[N * 40];

  void clear() {
    for(int i = 1; i <= n; ++i)
      w[i] = d[i] = vis[i] = 0, vector<int>().swap(G[i]);
    n = 0;
  }

  void add(int x, int y) {
    if(x && y) G[x].emplace_back(y);
  }

  void solve() {
    for(int i = 1; i <= n; ++i)
      f[i] = 0;
    queue<int> q;
    for(int i = 1; i <= n; ++i)
      for(int j : G[i])
        ++d[j];
    for(int i = 1; i <= n; ++i)
      if(d[i] == 0) q.push(i);
    if(!q.size()) {
      puts("-1");
      return ;
    }
    LL ans = -1;
    while(q.size()) {
      int u = q.front(); q.pop();
      vis[u] = 1;
      f[u] += w[u];
      ans = max(ans, f[u]);
      for(int v : G[u]) {
        f[v] = max(f[v], f[u]);
        --d[v];
        if(d[v] == 0) 
          q.push(v);
      }
    }
    for(int i = 1; i <= n; ++i)
      if(!vis[i]) {
        puts("-1");
        return ;
      }
    printf("%lld\n",ans);
  }
}

namespace SA {
  int sa[N], rk[N], ht[N], buc[N], id[N], ork[N];
  int st[18][N];

  void clear() {
    for(int i = 1; i <= n; ++i)
      sa[i] = rk[i] = ht[i] = buc[i] = id[i] = ork[i] = 0;
    memset(st, 0, sizeof st);
  }

  void build() {
    int m = 1 << 7, p = 0;
    memset(buc, 0, (m + 1) << 2);
    for(int i = 1; i <= n; ++i)
      buc[rk[i] = s[i]] ++;
    for(int i = 1; i <= m; ++i)
      buc[i] += buc[i - 1];
    for(int i = n; i >= 1; --i)
      sa[buc[rk[i]]--] = i;
    for(int w = 1; ; m = p, p = 0, w <<= 1) {
      for(int i = n - w + 1; i <= n; ++i)
        id[++p] = i;
      for(int i = 1; i <= n; ++i)
        if(sa[i] > w) id[++p] = sa[i] - w;
      memset(buc, 0, (m + 1) << 2);
      memcpy(ork, rk, (n + 1) << 2);
      p = 0;
      for(int i = 1; i <= n; ++i)
        buc[rk[i]] ++;
      for(int i = 1; i <= m; ++i)
        buc[i] += buc[i - 1];
      for(int i = n; i >= 1; --i)
        sa[buc[rk[id[i]]]--] = id[i];
      for(int i = 1; i <= n; ++i)
        rk[sa[i]] = ((ork[sa[i - 1]] == ork[sa[i]] && ork[sa[i - 1] + w] == ork[sa[i] + w]) ? p : ++p);
      if(p == n) break;
    }
    for(int i = 1, h = 0; i <= n; ++i) {
      if(h) --h;
      while(s[i + h] == s[sa[rk[i] - 1] + h]) ++h;
      ht[rk[i]] = h;
    }
    for(int i = 1; i <= n; ++i)
      st[0][i] = ht[i];
    for(int i = 1; i <= 17; ++i)
      for(int j = 1; j <= n; ++j)
        if(j + (1 << (i - 1)) <= n) st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
        else st[i][j] = 0;
  }

  int STquery(int l, int r) {
    int p = 31 - __builtin_clz(r - l + 1);
    return min(st[p][l], st[p][r - (1 << p) + 1]);
  }

  pair<int, int> query(int x, int len) {
    int lans = x, rans = x;
    for(int l = 2, r = x; l <= r; ) {
      int mid = (l + r) / 2;
      if(STquery(mid, x) >= len) lans = mid - 1, r = mid - 1;
      else l = mid + 1;
    }
    for(int l = x + 1, r = n; l <= r; ) {
      int mid = (l + r) / 2;
      if(STquery(x + 1, mid) >= len) rans = mid, l = mid + 1;
      else r = mid - 1;
    }
    return make_pair(lans, rans);
  }
}

struct SegmentTree {
  struct Node {
    int id;
    int lc, rc;
  }tr[N * 20];
  #define mid (l + r) / 2
  int tot;
  void modify(int &k, int l, int r, int pos, int v) {
    if(r < pos || pos < l) return ;
    tr[++tot] = tr[k], k = tot;
    if(k) Graph::add(++Graph::n, tr[k].id);
    tr[k].id = Graph::n;
    if(l == r) {
      Graph::add(tr[k].id, v);
      return ;
    }
    modify(tr[k].lc, l, mid, pos, v);
    modify(tr[k].rc, mid + 1, r, pos, v);
    if(tr[tr[k].lc].id) 
      Graph::add(tr[k].id, tr[tr[k].lc].id);
    if(tr[tr[k].rc].id)
      Graph::add(tr[k].id, tr[tr[k].rc].id);
    return ;
  }
  void query(int k, int l, int r, int L, int R, int v) {
    if(r < L || R < l || !k) return ;
    if(L <= l && r <= R && tr[k].id) {
      Graph::add(v, tr[k].id);
      return ;
    }
    query(tr[k].lc, l, mid, L, R, v);
    query(tr[k].rc, mid + 1, r, L, R, v);
  }
  #undef mid
}seg;

struct itv {
  int st, len;
}a[N], b[N];

vector<int> va[N];
vector<int> vb[N];
void buildEdge() {
  for(int i = 1; i <= n; ++i)
    va[i].clear(), vb[i].clear();
  for(int i = 1; i <= na; ++i)
    va[a[i].len].emplace_back(i);
  for(int i = 1; i <= nb; ++i)
    vb[b[i].len].emplace_back(i);
  int rt = 0;
  for(int i = n; i >= 1; --i) {
    for(int x : va[i])
      seg.modify(rt, 1, n, SA::rk[a[x].st], x);
    for(int x : vb[i]) {
      pair<int, int> rng = SA::query(SA::rk[b[x].st], b[x].len);
      seg.query(rt, 1, n, rng.first, rng.second, x + na);
    }
  }
}

void clear() {
  Graph::clear();
  seg.tot = 0;
}

void solve() {
  scanf("%s",s + 1);
  n = strlen(s + 1);
  SA::build();
  read(na);
  for(int i = 1; i <= na; ++i) {
    int l, r; read(l, r);
    a[i].st = l, a[i].len = r - l + 1;
    Graph::w[i] = a[i].len;
  }
  read(nb);
  for(int i = 1; i <= nb; ++i) {
    int l, r; read(l, r);
    b[i].st = l, b[i].len = r - l + 1;
  }
  Graph::n = na + nb;
  buildEdge();
  read(m);
  for(int i = 1; i <= m; ++i) {
    int x, y; read(x, y);
    Graph::add(x, y + na);
  }
  Graph::solve();
  clear();
}

int main() {
  int T; read(T);
  while(T--) solve();
}

posted @ 2023-11-02 21:57  DCH233  阅读(28)  评论(0编辑  收藏  举报