首页 > 其他分享 >题解 P9196【[JOI Open 2016] 销售基因链】

题解 P9196【[JOI Open 2016] 销售基因链】

时间:2023-06-13 13:11:32浏览次数:49  
标签:pre suf return P9196 int 题解 dfn queries JOI

套路题,来讲个套路解法。

如果没有后缀的要求,答案就是 trie 树的子树内字符串数量。现在加上了后缀,尝试继续使用 trie 树解决问题。

我们建立两棵 trie 树 \(T_1,T_2\),其中 \(T_1\) 是正常的 trie 树,\(T_2\) 是每个字符串翻转后的 trie 树。这样的话,包含给定后缀的字符串在 \(T_2\) 上构成一棵子树。例如,样例一中的两棵 trie 树如下:

考虑一个询问意味着什么,其实就是查询同时在 \(T_1\) 一棵子树和 \(T_2\) 一棵子树内的字符串数。例如 \((\texttt{AU},\texttt{C})\) 就是查询同时在 \(T_1\) 的节点 \(2\) 的子树和 \(T_2\) 的节点 \(1\) 的子树内的字符串数,只有 \(\texttt{AUGC}\) 符合要求,因此答案为 \(1\)。

把每个字符串抽象为坐标 \((x,y)\) 的点,其中 \(x,y\) 分别是 \(T_1,T_2\) 上字符串终止节点的 dfs 序,那么一次询问就是查询一个矩形内部点的数量,是二维数点问题,扫描线维护即可。

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define per(x,y,z) for(int x=(y);x>=(z);x--)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;

mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
    uniform_int_distribution<int> dist(L, R);
    return dist(rnd);
}

template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}

const int N = 2e6+5;

int n, m, ans[N];
string s, t;
vector<tuple<int, int>> dots;
vector<tuple<int, int, int, int>> queries;

int f(char c) {
    if(c == 'A') return 0;
    if(c == 'G') return 1;
    if(c == 'U') return 2;
    if(c == 'C') return 3;
    return -1;
}

struct Trie {
    int son[N][4], tot, sz[N], dfn[N], tms;
    int insert(string s) {
        int u = 0;
        for(char c : s) {
            int k = f(c);
            if(!son[u][k]) son[u][k] = ++tot;
            u = son[u][k];
        }
        return u;
    }
    int find(string s) {
        int u = 0;
        for(char c : s) {
            int k = f(c);
            if(!son[u][k]) return -1;
            u = son[u][k];
        }
        return u;
    }
    void dfs(int u) {
        dfn[u] = tms++;
        sz[u] = 1;
        rep(i, 0, 3) {
            if(son[u][i]) {
                dfs(son[u][i]);
                sz[u] += sz[son[u][i]];
            }
        }
    }
}pre, suf;

struct BIT {
    int c[N];
    int lowbit(int x) {return x & (-x);}
    void add(int x, int k) {++x; for(; x < N; x += lowbit(x)) c[x] += k;}
    int ask(int x) {++x; int k = 0; for(; x; x -= lowbit(x)) k += c[x]; return k;}
}bit;

int main() {
    // freopen("debug.log", "w", stderr);
    scanf("%d%d", &n, &m);
    rep(i, 1, n) {
        cin >> s;
        int x = pre.insert(s);
        reverse(s.begin(), s.end());
        int y = suf.insert(s);
        dots.emplace_back(x, y);
    }
    pre.tms = suf.tms = 0;
    pre.dfs(0);
    suf.dfs(0);
    for(auto& [x, y] : dots) {
        x = pre.dfn[x];
        y = suf.dfn[y];
    }
    rep(i, 1, m) {
        cin >> s >> t;
        reverse(t.begin(), t.end());
        int u = pre.find(s), v = suf.find(t);
        if(u == -1 || v == -1) ans[i] = 0;
        else {
            // debug("# %d : %d %d %d %d\n", i, pre.dfn[u], suf.dfn[v], pre.dfn[u]+pre.sz[u]-1, suf.dfn[v]+suf.sz[v]-1);
            queries.emplace_back(pre.dfn[u]-1, suf.dfn[v]-1, i, +1);
            queries.emplace_back(pre.dfn[u]-1, suf.dfn[v]+suf.sz[v]-1, i, -1);
            queries.emplace_back(pre.dfn[u]+pre.sz[u]-1, suf.dfn[v]-1, i, -1);
            queries.emplace_back(pre.dfn[u]+pre.sz[u]-1, suf.dfn[v]+suf.sz[v]-1, i, +1);
        }
    }
    sort(dots.begin(), dots.end());
    sort(queries.begin(), queries.end());
    // for(auto [x, y, id, mul] : queries) debug("* %d %d %d %d\n", x, y, id, mul);
    int ds = (int)dots.size(), qs = (int)queries.size(), did = 0, qid = 0;
    // debug("= %d %d\n", pre.tot, suf.tot);
    rep(i, 0, pre.tot) {
        // debug("? %d\n", i);
        while(did < ds) {
            auto [x, y] = dots[did];
            if(x != i) break;
            // debug("+ %d/%d : %d %d\n", did, ds, x, y);
            bit.add(y, 1);
            ++did;
        }
        while(qid < qs) {
            auto [x, y, id, mul] = queries[qid];
            if(x != i) break;
            // debug("! %d/%d : %d %d %d %d -> %d\n", qid, qs, x, y, id, mul, bit.ask(y));
            ans[id] += mul * bit.ask(y);
            ++qid;
        }
    }
    rep(i, 1, m) printf("%d\n", ans[i]);
    return 0;
}

标签:pre,suf,return,P9196,int,题解,dfn,queries,JOI
From: https://www.cnblogs.com/ruierqwq/p/LG-P9196.html

相关文章

  • C++ Windows.h max宏与std::max冲突问题解决
    C语言引入的宏支持了一定程度的元编程,但它仅仅是简单的字符串替换,这种“六亲不认”的操作很容易导致一些编译错误。这篇文章介绍了一种场景:项目同时引入了老的C头文件,里面用宏定义了一些宏函数;还引入了C++的头文件,里面用其他方式定义了一些同名函数。具体到问题本身,这个......
  • Not Another Linear Algebra Problem 题解
    题意:自己看。首先我们知道我们唯一能找到的题解在hos_lyric的代码里。把它放在这里:(由bikuhiku提供)\[\begin{aligned}&U\subseteq\mathbb{F}_p^n,\text{subspace}\\&a(U):=\#\{p\in\text{Aut}(\mathbb{F}_p^n)|\text{Ker}(p-\text{id})=U\}\\&b(U):=......
  • 【问题解决1】fatal error: X11/XXXX.h: No such file or directory
    问题现象编译鸿蒙代码时,报如下类似的错误:错误1:错误2:解决方法step1:安装依赖文件sudoapt-getinstallapt-filesudoapt-fileupdatestep2:查找报错文件apt-filesearchXXXX.h例如:报错的是Intrinsic.h或上图中的Xrandr.h,对应如下:apt-filesearchIntrinsic......
  • vue调用百度api时,跨域问题解决方案
    最近在调用百度地图,文字转语音接口的时候,用vue,js来前端实现转换,及时语音播报,遇到点问题;1.之前直接不用accessToken,一个连接拼接抓取的,已经失效了。2.查看百度文档,更新后的接口,按照文档nodejs格式,一直都是报跨域问题,单独在headers中加'Access-Control-Allow-Origin':'*'无效。......
  • [ABC305C] Snuke the Cookie Picker题解
    题目大意有一个\(H\timesW\)的网格,一种有一个矩形,矩形中间有一个点被挖空,求这个点的坐标。(.表示空白,#表示矩形内的点)解析观察我们可以发现,每一矩形内的个点上下左右至少会有两个是#。如图:而每一个在矩形外的点上下左右最多只有一个#。所以我们只需要找的一个.的上......
  • [ABC305D] Sleep Log题解
    题目大意给\(N\)个时刻:当\(i\)为奇数时,\(A_i\)表示刚刚起床的时刻。当\(i\)为偶数时,\(A_i\)表示开始睡觉的时刻。有\(Q\)次询问,每次求在\([l,r]\)区间内睡了多长时间。分析首先我们要考虑处理边界情况。每一次二分查找第一个大于等于\(l\)和\(r\)的时刻......
  • VM虚拟机模板,克隆或导入后网络不通问题解决办法
    出于工作需要可能需要对VM虚拟机制作模板,并导出为.vof文件,并根据vof模板文件导入为新的虚拟机,但是当导入后会发现网络不通,现将网络问题解决办法进行记录:本次实验OS为Centos7,网卡默认配置文件名为ifcfg-ens331.保留默认网卡网卡目录:/etc/sysconfig/network-scripts/保留默认......
  • CF113B Petr# 题解
    最近在做字符串的题,正好就给我随机了一道这个(题意给你一个字符串\(s\)以及一个开头串\(s_{begin}\)和结尾串\(s_{end}\),问该字符串中有多少个不同的子串,满足以\(s_{begin}\)开头,以\(s_{end}\)结尾。两个子串不同,当且仅当两个子串长度不同,或长度相同但至少有一个位置上......
  • 【P8819 [CSP-S 2022]】 星战 题解(图论 + 哈希)
    图论+哈希。Link.因为实在是太妙了所以写个题解。Solution因为每个点的出度都为\(1\),所以从任意一点出发永远可以走下去,故每次只需判断每个点度数是否为\(1\)即可。然后一三操作显然直接\(O(1)\)维护,\(50\pts\)。考虑二四操作。每次操作显然对点\(u\)的出度......
  • [ABC212E] Safety Journey 题解
    SafetyJourney题目大意给定一张缺少了\(m\)条边的\(n\)个点的完全图和一个正整数\(k\),你需要求出满足以下条件的序列\(A\)的数量:\(A\)的长度为\(k+1\)。\(A_0=A_k=1\)。\(\forall0\lei\lek-1\),点\(A_i\)和点\(A_{i+1}\)之间存在边。思路分析图上计数,考......