BZOJ 2754 喵星球上的点名

题意:

太长了不说了直接撂这了

https://www.lydsy.com/JudgeOnline/problem.php?id=2754

Sol:

如果(ac)自动机的话可以把(fail)树抽出来然后建虚树,有点难写。

(SAM)的话问题转化完以后和(sa)是一样的....

按照(sa)的习惯我们把名和姓还有问分别串起来,然后做(SA)

第一问就是对于每个(Len)合法的区间有多少种颜色,同时排除问题串的颜色。

离线左端点排序做出(nxt)维护下一个颜色出现的位置,(BIT)点修就好了。

第二问就是每个点被多少区间覆盖

实际上就是碰见左端点++,碰见右端点就消掉这个右端点所属询问的左端点的贡献

要让区间左右端点分别都从小到大排个序,不然会有锅。

原因是一位一位的扫要求单增。

还有一个地方就是数组要开很大...不然会挂...

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N = 4e5 + 7;
const int lim = 4e5;
typedef long long LL;
inline int max(int a, int b){return a > b ? a : b;}
inline int min(int a, int b){return a > b ? b : a;}
int x[N*2], y[N*2], sa[N*2], rk[N*2], c[N*2];
int m = lim, n; int het[N*2], qlog[N*2], st[N*2][23];
//#define R register
int ss[N*2];int totp;
inline void getSA() {
  for (int i = 1; i <= m; i++) c[i] = 0;
  for (int i = 1; i <= n; i++) c[x[i] = ss[i]]++;
  for (int i = 1; i <= m; i++) c[i] += c[i - 1];
  for (int i = 1; i <= n; i++) sa[c[x[i]]--] = i;
  for (int siz = 1, p = 0; siz <= n; siz <<= 1, p = 0) {
    for (int i = n - siz + 1; i <= n; i++) y[++p] = i;
    for (int i = 1; i <= n; i++) if (sa[i] > siz) y[++p] = sa[i] - siz;
    for (int i = 1; i <= m; i++) c[i] = 0;
    for (int i = 1; i <= n; i++) c[x[y[i]]]++;
    for (int i = 1; i <= m; i++) c[i] += c[i - 1];
    for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
    std :: swap(x, y), x[sa[1]] = 1, p = 1;
    for (int i = 2; i <= n; i++) x[sa[i]] = 
      (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + siz] == y[sa[i - 1] + siz]) ? p : ++p;
    if (p == n) break; m = p;
  } int k = 0;
  memset(het, 0, sizeof(het));
  for (int i = 1; i <= n; i++) rk[sa[i]] = i;
  for (int i = 1; i <= n; i++) if (rk[i] != 1) {
    if (k) k--;
    int j = sa[rk[i] - 1];
    while(j + k <= n && i + k <= n && ss[i + k] == ss[j + k]) k++;
    het[rk[i]] = k;
  } qlog[1] = 0;
  memset(st, 0, sizeof(st));
  for (int i = 2; i <= lim; i++) qlog[i] = qlog[i / 2] + 1;
  for (int i = 1; i <= lim; i++) st[i][0] = het[i];
  int logw = qlog[n];
  for (int i = 1; i <= logw; i++) for (int j = 1; j + (1 << i) - 1 <= n; j++)
    st[j][i] = min(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
  memset(c, 0, sizeof(c));
}
const int inf = 1e9 + 7;
inline int query(int x, int y) { if (x > y) std :: swap(x, y);
  if(x == y) return inf; x += 1; int logw = qlog[y - x + 1], ans;
  ans = min(st[x][logw], st[y - (1 << logw) + 1][logw]); return ans;
} 

int sq;int totc, cntx;int fq, col[2*N];
#define lbt(x) x & -x;
#define upmax 3e5
inline void Modify(int x, int k) {while (x <= upmax) c[x] += k, x += lbt(x);}
inline int query(int x) {
  int res = 0; while (x > 0) res += c[x], x -= lbt(x); return res;
}
struct ask {int l, r, id, x, ans;}q[N*2];
inline int cmp(ask a, ask b) {return a.l == b.l ? a.r < b.r : a.l < b.l;}
inline int cmp2(ask a, ask b) {return a.id < b.id;}
int upadd = 1e4 + 3; int qPos[N], qsum; int queryLen[2*N];
struct ANS {int q1, q2;} ansq[N*2];
void init(){
  scanf("%d%d", &n, &sq), totp = n;
  for (int i = 1; i <= n; i++) {
    int Len; scanf("%d", &Len), totc++;
    for (int j = 1; j <= Len; j++) 
      scanf("%d", &ss[++cntx]), col[cntx] = totc;
    ss[++cntx] = ++upadd, col[cntx] = 0;
    scanf("%d", &Len);//, fir[++fq] = cntx + 1;
    for (int j = 1; j <= Len; j++) 
      scanf("%d", &ss[++cntx]), col[cntx] = totc;
    ss[++cntx] = ++upadd, col[cntx] = 0;
  } 
  for (int i = 1; i <= sq; i++) {
    int Len; scanf("%d", &Len); qPos[i] = cntx + 1; queryLen[i] = Len;
    for (int j = 1; j <= Len; j++) scanf("%d", &ss[++cntx]), col[cntx] = 0;
    ss[++cntx] = ++upadd, col[cntx] = 0;
  }
} int afc[N*2];
void dye() {
  for (int i = 1; i <= cntx; i++) afc[i] = col[sa[i]];
}
inline int findL(int l, int r, int x, int req) {
  while (l < r) {
    int MID = (l + r) >> 1;
    if (query(MID, x) >= req) r = MID;
    else l = MID + 1;
  } return l;
}
inline int findR(int l, int r, int x, int req) {
  while (l < r) {
    int MID = (l + r + 1) >> 1;
    if (query(x, MID) >= req) l = MID;
    else r = MID - 1; 
  } return r;
} int pre[N*2], nxt[N*2], b[N*2];
void solve1() {
  for (int i = 1; i <= sq; i++) {
    int queryx = rk[qPos[i]];
    int l = findL(1, queryx, queryx, queryLen[i]);
    int r = findR(queryx, cntx, queryx, queryLen[i]);
    q[i].l = l, q[i].r = r, q[i].id = i;
  } std :: sort(q + 1, q + sq + 1, cmp);
  for (int i = 1; i <= n; i++) if(1) {
    nxt[pre[afc[i]]] = i;
    if (!pre[afc[i]] && afc[i] > 0) b[i] = 1;
    pre[afc[i]] = i;
  }
  for (int i = 1; i <= n; i++) if(b[i]) Modify(i, b[i]);
  for (int i = 1; i <= n; i++) if (!nxt[i]) nxt[i] = upmax + 1;
  q[0].l = 1;
  for (int i = 1; i <= sq; i++) {
    if (q[i - 1].l != q[i].l)
      for (int j = q[i - 1].l; j <= q[i].l - 1; j++)
        if(afc[j]) Modify(nxt[j], 1);
    q[i].ans = query(q[i].r) - query(q[i].l - 1);
  } std :: sort(q + 1, q + sq + 1, cmp2);
  for (int i = 1; i <= sq; i++) printf ("%d
", q[i].ans);
} 
#define clear(x) memset(x,0,sizeof(x))
int ansc[N*2];
struct rqq {int l, r, id;}rq[N*2];
inline int cmp3(rqq a, rqq b) {return a.r == b.r ? a.l < b.l : a.r < b.r;}
void solve2() {
  memset(pre, 0, sizeof(pre)), memset(c, 0, sizeof(c));
  std :: sort(q + 1, q + sq + 1, cmp);
  for (int i = 1; i <= sq; i++) 
    rq[i].l = q[i].l, rq[i].r = q[i].r, rq[i].id = q[i].id;
  std :: sort(rq + 1, rq + sq + 1, cmp3);
  for (int i = 1, j = 1, k = 1; i <= n; i++) {
    for ( ; q[j].l == i && j <= sq; j++) Modify(i, 1);
    if(afc[i]) ansc[afc[i]] += query(i) - query(pre[afc[i]]);
    for ( ; rq[k].r == i && k <= sq; k++) Modify(rq[k].l, -1);
    pre[afc[i]] = i;
  }
  for (int i = 1; i <= totp; i++) printf ("%d ", ansc[i]); puts("");
}
int main() {
  init(), n = cntx, getSA(), dye(), solve1(), solve2();
return 0;
}
原文地址:https://www.cnblogs.com/cjc030205/p/11638095.html