2019 ICPC 南京 F 题 Paper Grading

2 篇文章 0 订阅
1 篇文章 0 订阅

题目链接

题意

给出 n n n 个字符串, m m m 个操作,操作有两种,一种是交换 i , j i,j i,j 两个字符串的位置,一种是查询 [ l , r ] [l,r] [l,r] 范围内与给出的字符串 q q q 的最长公共前缀 ( L C P ) (LCP) (LCP) 至少为 k k k 的字符串有多少个。

题解

对给出的字符串建一棵 T r i e Trie Trie,那么以某个串 a a a T r i e Trie Trie 上的节点的那颗子树下面的子串的 L C P LCP LCP 就至少是 a a a 了,把结点转成 d f s dfs dfs 序,问题就转化成了带修改的二维数点, c d q cdq cdq 即可,复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

代码:

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
#define debug(a) cout << #a": " << a << endl;
#define mst(a, b) memset(a, b, sizeof(a))
#define ALL(x) x.begin(), x.end()
#define lc rt << 1
#define rc rt << 1 | 1
#define X first
#define Y second
inline int lowbit(int x) { return x & -x; }
typedef long long ll;
typedef long long LL;
typedef unsigned long long ULL;
typedef double db;
typedef pair<int, int> pii;
typedef pair<int, LL> pil;
const int N = 1e6 + 10;
const int M = 1e6 + 10;
const int maxn = 2e3 + 10;
const int maxm = 4e3 + 10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 998244353;
const db eps = 1e-11;
const db pi = acos(-1.0);

struct P {
    int op, qt, ql, qr, val;
}p[M];
char s[N];
int ch[26][N];
int id[N];
int dfn[N];
int en[N];
int qans[N];
int idans[M];
int tot;
int totDfn;
int bit[N];

void update(int pos, int val) {
    ++pos;
    for (; pos < N; pos += lowbit(pos))
        bit[pos] += val;
}
int Qu(int pos) {
    int res = 0;
    ++pos;
    for (; pos; pos -= lowbit(pos))
        res += bit[pos];
    return res;
}
int ins(int len) {
    int root = 0;
    for (int i = 1; i <= len; i++) {
        int idx = s[i] - 'a';
        int& nxt = ch[idx][root];
        if (!nxt)
            nxt = ++tot;
        root = nxt;
    }
    return root;
}
int query(int len) {
    int root = 0;
    for (int i = 1; i <= len; i++) {
        int idx = s[i] - 'a';
        if (!ch[idx][root])
            return -1;
        root = ch[idx][root];
    }
    return root;
}
void dfs(int u) {
    dfn[u] = ++totDfn;
    for (int i = 0; i < 26; i++) if (ch[i][u])
        dfs(ch[i][u]);
    en[u] = totDfn;
}
void cdq(int L, int R) {
    if (L >= R)
        return ;
    int mid = L + R >> 1;
    cdq(L, mid);
    cdq(mid + 1, R);
    for (int i = mid + 1, j = L; i <= R; i++) {
        for (; j <= mid && p[j].qr <= p[i].qr; j++) if (p[j].op == 1) {
            update(p[j].ql, p[j].val);
        }
        if (p[i].op == 2)
            qans[idans[p[i].qt]] += Qu(p[i].ql) * p[i].val;
    }
    for (int i = mid + 1, j = L; i <= R; i++) {
        for (; j <= mid && p[j].qr <= p[i].qr; j++) if (p[j].op == 1) {
            update(p[j].ql, -p[j].val);
        }
    }
    sort(p + L, p + R + 1, [](P a, P b) {
            return a.qr < b.qr;
        });
}
int main() {
#ifdef purple_bro
    freopen("in.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;

    cin >> n >> m;

    for (int i = 1; i <= n; i++) {
        cin >> s + 1;
        int len = strlen(s + 1);
        id[i] = ins(len);
    }

    dfs(0);

    int q = 0;
    int qu = 0;

    for (int i = 1; i <= n; i++)
        p[++q] = {1, 1, i, dfn[id[i]], 1};

    for (int i = 1; i <= m; i++) {
        int opt;
        cin >> opt;
        if (opt == 1) {
            int x, y;
            cin >> x >> y;
            p[++q] = {opt, i, x, dfn[id[x]], -1};
            p[++q] = {opt, i, y, dfn[id[y]], -1};
            swap(id[x], id[y]);
            p[++q] = {opt, i, x, dfn[id[x]], 1};
            p[++q] = {opt, i, y, dfn[id[y]], 1};
        } else {
            int k, l, r;
            cin >> s + 1 >> k >> l >> r;
            int d = query(k);
            idans[i] = ++qu;
            if (d == -1)
                qans[qu] = 0;
            else {
                p[++q] = {opt, i, r, en[d], 1};
                p[++q] = {opt, i, l - 1, dfn[d] - 1, 1};
                p[++q] = {opt, i, l - 1, en[d], -1};
                p[++q] = {opt, i, r, dfn[d] - 1, -1};
            }
        }
    }

    cdq(1, q);

    for (int i = 1; i <= qu; i++)
        cout << qans[i] << "\n";

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值