• BJOI2016 IP地址


    题目链接

    Description

    给定 (n)(01) 模式串。(q) 次询问:

    每次询问给定一个 (01) 串:

    • 设给这个串匹配的串是在模式串中存在的他的最长前缀
    • ([a, b]) 时刻内,这个匹配的串变了多少次。

    Solution

    这题很坑没有给出 (01) 串的长度数据范围,不过应该能读进来说明是个字符串总数的复杂度是够的。

    统计两个串符合某种前缀关系,首先想到 ( ext{Trie})

    显然这个答案符合区间可加性,设答案 (=) 匹配串在前 (r) 个时刻的变换次数 (-) 匹配串在前 (l) 个时刻的变换次数。拆完询问后,不妨考虑离线,考虑从小到大加入一个模式串到 ( ext{Trie}) 中,然后统计相应位置下的答案。

    考虑在 (Trie) 树上动态维护每个节点的信息:

    • (cnt_i) 表示从开始到当前时刻,如果匹配串在这个节点,它的最长前缀会被修改多少次

    比较显然的是,如果存在两个模式串 (a,b)(a)(b) 的前缀。那么当 (b) 存在的时候,(a) 当前要进行加入 / 删除, (a) 的修改不会影响 (b) 节点的子树(因为 (b) 节点的子树的最长前缀还是 (b)),但是会影响 (a) 的子树除了 (b) 的子树的部分,让他们的 (cnt)(+1)。这启示我们再弄一个信息:

    • (st_i) 表示 (i) 这个节点当前有没有模式串

    那么每次修改 / 删除一个模式串 (a),就把 (a)( ext{Trie}) 下的从上到下不断扩展,除非遇到 (st)( ext{True}),那么停止。

    然后我们发现这个东西其实和线段树的 ( ext{pushdown}) 很像,然后再想想是可以这么搞的,弄个加法 ( ext{tag}) 就行了,所以就 ( ext{OK}) 了。值得注意的是 ( ext{pushdown}) 仅能用在祖先全部处理完的情况下,不能胡乱加标记,否则修改的先后顺序会出现混乱,这是我之前尝试的(因为我不懂线段树 QAQ)。

    时间复杂度

    (O(线性))

    Code

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <vector>
    using namespace std;
    
    const int N = 100005;
    
    int n, m, tr[N * 64][2], idx, cnt[N * 64];
    int add[N * 64], pos[N], ans[N];
    
    bool st[N * 64], opt[N];
    
    char op[4], s[N][64], g[N][64];
    
    vector<int> q[N];
    
    
    void inline pushdown(int p) {
    	if (!add[p]) return;
    	if (!tr[p][0]) tr[p][0] = ++idx;
    	if (!tr[p][1]) tr[p][1] = ++idx;
    	if (!st[tr[p][0]]) add[tr[p][0]] += add[p], cnt[tr[p][0]] += add[p];
    	if (!st[tr[p][1]]) add[tr[p][1]] += add[p], cnt[tr[p][1]] += add[p];
    	add[p] = 0;
    }
    
    void inline insert(int id, bool tag) {
    	int p = 0;
    	for (int i = 0; s[id][i]; i++) {
    		int ch = s[id][i] - '0';
    		pushdown(p);
    		if (!tr[p][ch]) tr[p][ch] = ++idx;
    		p = tr[p][ch];
    	}
    	cnt[p]++, add[p]++;
    	st[p] = tag;
    }
    
    int inline query(int id) {
    	int p = 0;
    	for (int i = 0; g[id][i]; i++) {
    		int ch = g[id][i] - '0';
    		if (!tr[p][ch]) return cnt[p];
    		p = tr[p][ch];
    		pushdown(p);
    	}
    	return cnt[p];
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++) {
    		scanf("%s%s", op, s[i]);
    		opt[i] = op[0] == 'A';
    	}
    	for (int i = 1, a, b; i <= m; i++) {
    		scanf("%s%d%d", g[i], &a, &b);
    		q[a].push_back(i);
    		q[b].push_back(i); 
    	}
    	for (int i = 1; i <= n; i++) {
    		insert(i, opt[i]);
    		for (int j = 0; j < q[i].size(); j++) {
    			int id = q[i][j];
    			ans[id] = query(id) - ans[id];
    		}
    	}
    	for (int i = 1; i <= m; i++) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    ajax 异步问题
    mysql update 报 You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode
    JSON string 和 object 转换
    Mybatis insert 返回主键
    switch case 的值
    $(this).attr("checked") 用jquery取checkbox的值 返回undefined
    7天入门JavaScript,第五天
    7天入门JavaScript,第四天
    7天入门JavaScript,第三天
    保持按钮的高亮状态
  • 原文地址:https://www.cnblogs.com/dmoransky/p/12603558.html
Copyright © 2020-2023  润新知