bzoj1014 火星人prefix

2023-11-02 11:38
文章标签 prefix 火星人 bzoj1014

本文主要是介绍bzoj1014 火星人prefix,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

火星人prefix

题目背景:

bzoj1014

分析:我有一句XXX不知道当不当讲,但是真的太恶心了!!!

这道题本来的做法是对于每一个节点,维护以它为根的子树的字符串的hash值就可以了,我是用无旋treap来实现的,然后每一次合并和分割的时候,就可以直接update像上维护即可,但是当时开始的时候我的代码不断地T飞,然后我尝试优化了很多波的常数,最后发现并没有什么卵用,然后就不停地东改改西凑凑,然后最终还是T掉了,然后学长突然表示,可以把hash改成自然溢出试试,然后,就过了,当时我就表示,如果以后不卡自然溢出,我一定死都不用qnq。本体就是利用平衡树来维护当前的字符串,然后直接进行对以xy开头的两个字符串,二分长度,比对当前的hash值是否相同,每一次split相应的区间就可以了,所以询问的操作应该是二分的操作套上平衡树的操作,应该是log2n所以说,本题的最坏的复杂度应该为nlog2n(询问操作),其余操作均可以logn实现,(不过本题用treap写的确速度比较慢······)

Source

#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <ctime>inline char read() {static const int IN_LEN = 1048576;static char buf[IN_LEN], *s, *t;if (s == t) {t = (s = buf) + fread(buf, 1, IN_LEN, stdin);if (s == t) return -1;}return *s++;
}/*
template<class T>
inline bool R(T &x) {static char c;static bool iosig;for (c = read(), iosig = false; !isdigit(c); c = read()) {if (c == -1) return false;if (c == '-') iosig = true;}for (x = 0; isdigit(c); c = read())x = (x << 3) + (x << 1) + (c ^ '0');if (iosig) x = -x;return true;
}
//*/const int OUT_LEN = 1048576;
char obuf[OUT_LEN], *oh = obuf;inline void writechar(char c) {if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;*oh++ = c;
}template<class T>
inline void W(T x) {static int buf[30], cnt;if (!x) writechar(48);else {if (x < 0) writechar('-'), x = -x;for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;while (cnt) writechar(buf[cnt--]);}
}inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); }///*
template<class T>
inline void R(T &x) {static char c;static bool iosig;for (c = getchar(), iosig = false; !isdigit(c); c = getchar())if (c == '-') iosig = true;for (x = 0; isdigit(c); c = getchar())x = (x << 3) + (x << 1) + (c ^ '0');if (iosig) x = -x;
}
//*/const int h = 31;
const int mod = 9875321;
const int MAXN = 150000 + 10;
char s[MAXN];
unsigned int hash_pow[MAXN];inline int get_rand() {static int rand_seed = 495;rand_seed += rand_seed << 1 | 1;return rand_seed;
}struct node *null;
struct node {node *lc, *rc;int size, rank;unsigned int hash;char key;node() {}node(char key) : lc(null), rc(null), size(1), rank(get_rand()),hash(key - 'a' + 1), key(key) {}inline void push_down() {}inline void maintain() {size = lc->size + 1 + rc->size;hash = lc->hash + (unsigned int)(key - 'a' + 1) * hash_pow[lc->size]+ (unsigned int)rc->hash * hash_pow[lc->size + 1];}
} data[MAXN], *rt;int top;struct Pair {node* first;node* second;Pair(node * first, node * second) : first(first), second(second) {}Pair() {}
};inline node* new_node(char key) {node *u = &data[top++];return *u = node(key), u;
}inline Pair split(node *u, int k) {if (u == null) return Pair(null, null);Pair t;u->push_down();if (k <= u->lc->size) t = split(u->lc, k), u->lc = t.second, t.second = u;else t = split(u->rc, k - u->lc->size - 1), u->rc = t.first, t.first = u;return u->maintain(), t;
}inline node* merge(node *u, node *v) {if (u == null) return v;if (v == null) return u;if (u->rank < v->rank) {u->push_down(), u->rc = merge(u->rc, v);return u->maintain(), u;} else {v->push_down(), v->lc = merge(u, v->lc);return v->maintain(), v;}
}inline node* build(char *a, int n) {static node *stack[MAXN], *u, *pre;int top = 0;for (int i = 0; i < n; ++i) {u = new_node(a[i]), pre = null;while (top && stack[top]->rank > u->rank)stack[top]->maintain(), pre = stack[top], stack[top--] = null;if (top) stack[top]->rc = u;u->lc = pre, stack[++top] = u;}while (top) stack[top--]->maintain();return stack[1];
}inline void insert(int pos, char c) {node *nr = new_node(c);Pair t = split(rt, pos);rt = merge(t.first, merge(nr, t.second));
}inline void change(int pos, char c) {Pair t1 = split(rt, pos - 1), t2 = split(t1.second, 1);t2.first->key = c, t2.first->hash = c - 'a' + 1;rt = merge(t1.first, merge(t2.first, t2.second));
}inline int query_hash(int pos, int length) {Pair t1 = split(rt, pos - 1), t2 = split(t1.second, length);int hash = t2.first->hash;return rt = merge(t1.first, merge(t2.first, t2.second)), hash;
}inline int query_lcp(int x, int y) {int r = std::min(rt->size - x, rt->size - y) + 2, l = 0;while (l + 1 < r) {int mid = l + r >> 1;if (query_hash(x, mid) == query_hash(y, mid)) l = mid;else r = mid;}return l;
}inline void pre() {hash_pow[0] = 1;for (int i = 1; i < MAXN; ++i) hash_pow[i] = hash_pow[i - 1] * h;
}char s_q[3], s_key[2];
int len, q, x, y, pos;
inline void solve() {scanf("%s", s), len = strlen(s);null = new_node(0), null->size = null->hash = 0, rt = build(s, len);R(q);while (q--) {scanf("%s", s_q);switch (s_q[0]) {case 'Q' :R(x), R(y), W(query_lcp(x, y)), writechar('\n');break;case 'R' :R(pos), scanf("%s", s_key), change(pos, s_key[0]);break;case 'I' :R(pos), scanf("%s", s_key), insert(pos, s_key[0]);break; }}
}int main() {pre();solve();flush();return 0;
}

 

这篇关于bzoj1014 火星人prefix的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/330354

相关文章

USACO Section 2.3 Longest Prefix

题意: 给你一大堆小字符串  和  一个大字符串  求  使用小字符串能拼出的大字符串的前缀最长是多少 思路: 由于数据不大  所以可以尝试扫描大字符串  每到一个位置用小字符串拼一下看看能拼多长  拼的最远距离就是答案 我用trie树来存小字符串集合  扫描大字符串时  如果该位置是可以向后延伸的(即之前能拼到这个位置) 那么我用一个标记在trie树上爬  每次发现一个小字符串结

CodeForces 487C Prefix Product Sequence

题意: 构造一个1~n的排列  使得n个前缀积%n是一个0~n-1的排列 思路: 首先确定n一定放最后  要不然会有%n会有多个0  这时n-1位置的前缀积为(n-1)! 接着讨论n  n为合数时只有n=4有解  因为如果n为合数一定可以拆成p*q的形式  明显pq|(n-1)! 然后构造ai=(i+1)*inv[i]  因为(i+1)*inv[i] == (j+1)*inv[j]时一

Prefix Sum 总结

注意:prefixsum一般都是用PrefixSum[n+1]的数组,prefix[0] = 0; 那么 因为i, j 是A里面的坐标,而prefixsum比A多了1;所以原来的sum[j] - sum[i-1]变成了 sum(i~j) = prefixsum(j + 1) - prefixsum(i); Interval Sum 思路:因为这个题目不需要modify数组操作

leetcode --- Longest Common Prefix

最长公共前缀(Longest  Common  Prefix) 题目:Write a function to find the longest common prefix string amongst an array of strings. 题目链接:https://leetcode.com/problems/longest-common-pref

leetcode 刷题之路 8 Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings. 寻找一组字符串的最长公共前缀,比较简单,直接贴上程序: accepted answer: class Solution {public:string longestCommonPrefix(vector<str

Leetcode25: Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings. 求若干字符串的最长公共前缀。 首先若无字符串,返回“”;接下来求得其中最短字符串的长度len,比较公共前缀只需最多比较len次;最后比较所有字符串里每一位上的字符。 class Solution {public:s

Leetcode171: Implement Trie (Prefix Tree)

Implement a trie with insert, search, and startsWith methods. Trie树又被称为字典树、前缀树,是一种用于快速检索的多叉树。Tried树可以利用字符串的公共前缀来节省存储空间。 但如果系统存在大量没有公共前缀的字符串,相应的Trie树将非常消耗内存。 Trie树的基本性质如下: 根节点不包括字符,除根节点外每个节点包括

LeetCode | Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings. 求字符串最长公共前缀,这题也没啥好说的,就代码可读性上说一说好了。 我写的虽然也是4ms虽然也没错,但是可读性上来说相对差了一点 class Solution {public:string longestComm

(LeetCode)Longest Common Prefix --- 最长公共前缀

Write a function to find the longest common prefix string amongst an array of strings. Subscribe to see which companies asked this question 解题分析: 首先要理解,如果是空串的话,那么说明前

CMake笔记之CMAKE_INSTALL_PREFIX详解以及ROS中可执行文件为什么会在devel_lib中

CMake笔记之CMAKE_INSTALL_PREFIX详解以及ROS中可执行文件为什么会在devel_lib中 code review! 文章目录 CMake笔记之CMAKE_INSTALL_PREFIX详解以及ROS中可执行文件为什么会在devel_lib中1.`CMAKE_INSTALL_PREFIX`详解变量作用设置 `CMAKE_INSTALL_PREFIX`示例影响范围常