【codechef October Challenge 2014】 Stringology is Magic

codechef 真的是太菜了。

上面一道水题,14年之后就没人A了。

以前A的人都是T的,跑的比我慢到不知道到哪里去了。

(还有随便一个全a串就卡成一百多秒的“AC”程序。。。)

发个链接:

原题地址

我的代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;
const int N = 2000005, LOG = 22;

int n, m, tp;
int Rt[N], gr[LOG][N];
char s[N], ssr[13];
LL sum[N];

namespace SE {
  const int M = N * 40;
  int tot, lc[M], rc[M], sum[M];
  void Modify(int &t, int l, int r, int x) {
    if (!t) t = ++tot;
    ++sum[t];
    if (l == r) return;
    int md = (l + r) >> 1;
    if (x <= md) Modify(lc[t], l, md, x);
    else Modify(rc[t], md + 1, r, x);
  }
  int Merge(int x, int y) {
    if (!x || !y) return x + y;
    int z = ++tot;
    lc[z] = Merge(lc[x], lc[y]);
    rc[z] = Merge(rc[x], rc[y]);
    sum[z] = sum[lc[z]] + sum[rc[z]];
    return z;
  }
  int Query_1(int t, int l, int r, int k) {
    if (l == r) return l;
    int md = (l + r) >> 1;
    if (sum[lc[t]] >= k) return Query_1(lc[t], l, md, k);
    return Query_1(rc[t], md + 1, r, k - sum[lc[t]]);
  }
  int Query_2(int t, int l, int r, int k) {
    if (l == r) return sum[t];
    int md = (l + r) >> 1;
    if (k <= md) return Query_2(lc[t], l, md, k);
    return sum[lc[t]] + Query_2(rc[t], md + 1, r, k);
  }
}

int tot = 1, lst = 1, ch[N][26], dep[N], rig[N], fa[N], ed[N];
int bit[N], id[N], rk[N], pos[N], son[N][26];
inline int New_(int _dep, int _fa, int _ri, int _e) {
  dep[++tot] = _dep; fa[tot] = _fa; rig[tot] = _ri; ed[tot] = _e;
  return tot;
}
void Ins(int a, int i) {
  int np = New_(dep[lst] + 1, 0, 1, i), p = lst;
  lst = np; pos[i] = tot;
  SE::Modify(Rt[tot], 1, n, i);
  for (; p && !ch[p][a]; p = fa[p]) ch[p][a] = np;
  if (!p) return void(fa[np] = 1);
  int q = ch[p][a];
  if (dep[q] == dep[p] + 1) return void(fa[np] = q);
  int y = New_(dep[p] + 1, fa[q], 0, ed[q]);
  memcpy(ch[y], ch[q], sizeof ch[y]);
  fa[q] = fa[np] = y;
  for (; p && ch[p][a] == q; p = fa[p]) ch[p][a] = y;
}
void Dfs(int x) {
  //cerr << "vis : " << x << endl;
  id[++tp] = x;
  for (int i = 0; i < 26; ++i) {
    if (son[x][i]) Dfs(son[x][i]);
  }
}
void Build() {
  for (int i = 1; i <= tot; ++i) ++bit[dep[i]];
  for (int i = 1; i <= tot; ++i) bit[i] += bit[i - 1];
  for (int i = 1; i <= tot; ++i) id[bit[dep[i]]--] = i;
  for (int i = 1; i <= tot; ++i) {
    int x = id[i]; gr[0][x] = fa[x];
    for (int j = 1; j < LOG; ++j) gr[j][x] = gr[j - 1][gr[j - 1][x]];
  }
  for (int i = tot; i >= 2; --i) {
    int x = id[i], y = fa[x];
    rig[y] += rig[x];
    Rt[y] = SE::Merge(Rt[x], Rt[y]);
    son[y][s[ed[x] - dep[y]] - 'a'] = x;
    //cerr << "son : " << y << " -- " << ed[x] - dep[y] << " --> " << x << endl;
  }
  Dfs(1);
  if (tp != tot) { cerr << "not tp equal!" << endl; throw; }
  //cerr << "id : ";
  for (int i = 1; i <= tot; ++i) {
    //cerr << id[i] << ' ';
    rk[id[i]] = i;
    sum[i] = sum[i - 1] + dep[id[i]] - dep[fa[id[i]]];
  }
  //cerr << endl << "finish build all" << endl;
}

pair<LL, LL> Solve_1(LL k1, int k2) {
  //cerr << "query 1 : " << k1 << ' ' << k2 << endl;
  int nl = 1, nr = tot, x = -1;
  for (int md; nl <= nr; ) {
    md = (nl + nr) >> 1;
    if (k1 <= sum[md]) {
      x = md; nr = md - 1;
    } else {
      nl = md + 1;
    }
  }
  if (x == -1) { cerr << "not found po!" << endl; throw; }
  k1 -= sum[x - 1];
  x = id[x];
  //cerr << "now x : " << x << ' ' << rig[x] << endl;
  if (k2 > rig[x]) { cerr << "k2" << endl; throw; }
  k2 = rig[x] - k2 + 1;
  int ps = SE::Query_1(Rt[x], 1, n, k2);
  //cerr << "note : " << k2 << ' ' << ps << endl;
  int len = k1 + dep[fa[x]];
  //cerr << "ans 1 : " << ps - len + 1 << ' ' << ps << endl;
  return make_pair(ps - len + 1, ps);
}
pair<LL, LL> Solve_2(int l, int r) {
  int x = pos[r], le = r - l + 1;
  for (int i = LOG - 1; ~i; --i) {
    if (gr[i][x] && dep[gr[i][x]] >= le) x = gr[i][x];
  }
  //cerr << "x : " << x << endl;
  int re = SE::Query_2(Rt[x], 1, n, r);
  LL rnk = sum[rk[x] - 1] + le - dep[fa[x]];
  //cerr << "note : " << rk[x] << ' ' << le << ' ' << dep[fa[x]] << endl;
  return make_pair(rnk, rig[x] - re + 1);
}

int main() {
  //freopen("zzz.in", "r", stdin);
  //freopen("zzz.out", "w", stdout);
  scanf("%s", s + 1);
  n = strlen(s + 1);
  reverse(s + 1, s + 1 + n);
  for (int i = 1; i <= n; ++i) Ins(s[i] - 'a', i);
  Build();
  
  scanf("%d", &m);
  for (LL l, r; m; --m) {
    scanf("%s%lld%lld", ssr, &l, &r);
    pair<LL, LL> re;
    if (ssr[0] == 'S') {
      re = Solve_1(l, r);
      re.first = n - re.first + 1;
      re.second = n - re.second + 1;
      swap(re.first, re.second);
    } else {
      l = n - l + 1; r = n - r + 1; swap(l, r);
      re = Solve_2(l, r);
    }
    printf("%lld %lld\n", re.first, re.second);
  }
  
  return 0;
}

 

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值