void init() {
head = -1;
idx = 0;
}
void add_to_head(int x) {
e[idx] = x, ne[idx] = head, head = idx++;
}
void add(int k, int x) {
e[idx] = x, ne[idx] = ne[k], ne[k] = idx++;
}
void remove(int k) {
ne[k] = ne[ne[k]];
}
void init() {
r[0] = 1, l[1] = 0;
idx = 2;
}
void add_to_head(int x) {
e[idx] = x;
l[idx] = 0;
r[idx] = r[0];
r[0] = idx++;
}
void add_to_back(int x) {
e[idx] = x;
r[idx] = 1;
l[idx] = l[1];
l[1] = idx++;
}
void addR(int k, int x) {
e[idx] = x;
l[idx] = k;
r[idx] = r[k];
l[r[k]] = idx;
r[k] = idx++;
}
void addL(int k, int x) {
e[idx] = x;
l[idx] = l[k];
r[idx] = k;
r[l[k]] = idx;
l[k] = idx++;
}
void remove(int k) {
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int stk[N], tt;
void push(int x) {
stk[++tt] = x;
}
void pop() {
--tt;
}
bool empty() {
return tt > 0;
}
int top() {
return stk[tt];
}
给定一个序列,求每一个数的左边,离他最近的满足某种性质的数的位置
这里是找离他最近的并且 自己 大于他的位置
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int stk[N], tt;
int main() {
int n, x;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
while (tt > 0 && stk[tt] >= x) tt--;
if (tt) cout << stk[tt] << ' ';
else cout << "-1 ";
stk[++tt] = x;
}
}
int q[N], hh, tt = -1;
void push(int x) {
q[++tt] = x;
}
void pop() {
hh++;
}
bool empty() {
return hh <= tt;
}
int front() {
return q[hh];
}
int back() {
return q[tt];
}
求滑动窗口里的最值
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int q[N], tt = - 1, hh;
int a[N];
int main() {
int n, k;
cin >> n >> k;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) {
if (hh <= tt && i - q[hh] >= k) hh++;
while (hh <= tt && a[q[tt]] >= a[i]) tt--;
q[++tt] = a[i];
if (i >= k - 1) cout << q[hh] << " ";
}
cout << endl;
tt = -1, hh = 0;
for (int i = 0; i < n; i++) {
if (hh <= tt && i - q[hh] >= k) hh++;
while (hh <= tt && a[q[tt]] <= a[i]) tt--;
q[++tt] = a[i];
if (i >= k - 1) cout << q[hh] << " ";
}
}
int find(const string & s, const string & p) {
int n = s.size(), m = p.size();
for (int i = 1; i <= n; i++) {
bool flag = true;
for (int j = 1; j <= m; j++)
if (s[i + j - 1] != p[j]) {
flag = flase;
break;
}
if (flag) return i;
}
return -1;
}
求模式串的最长前缀后缀长度,是每次失匹能少移动
如 ASDFASDF ,对应的前缀后缀长度为 00001233
这样如果在 第二个 S 失匹,只需要把字符串移动到 ASD ,让 D 与 文本串的字符去对比,尽可能利用已经匹配的信息
如何求模式串的最长前缀后缀长度?
自己和自己匹配
for (int i = 2, j = 0; i <= m; i++) {
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == [j + 1]) j++;
ne[i] = j;
}
for (int i = 1, j = 0; i <= n; i++) {
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j++;
if (j == m) return i - m + 1;
}
int son[N][26], cnt[N], idx;
void insert(const string & str) {
int p = 0;
for (char ch : str) {
if (!son[p][ch - 'a']) son[p][ch - 'a'] = ++idx;
p = son[p][ch - 'a'];
}
cnt[p]++;
}
int query(const string & str) {
int p = 0;
for (char ch : str) {
if (!son[p][ch - 'a']) return 0;
p = son[p][ch - 'a'];
}
return cnt[p];
}
int p[N];
int find(int x) {
return x == p[x] ? x : p[x] = find(p[x]);
}
void join(int x, int y) {
p[find(x)] = find(y);
}
堆结构是一种数组对象,它可以被看作为一颗完全二叉树。树中的每个结点与数组中存放该结点中值的那个元素相对应。
设数组A的长度为len,二叉树的节点个数为size,size$<=$len,则A[i]存储二叉树中编号为i的节点值$(1<=i<=size)$而A[size]以后的元素并不属于相应的堆,树的根为A[1],并且利用完全二叉树的性质,我们很容易求得第i个结点得父亲结点左孩子结点和右孩子结点
更重要的是,堆具有这样的一个性质,对除跟以外的每个结点i,A[parent[i]]>=a[i]。也就是说除根结点以外,所有结点的值都不能超过父亲的值,这样就推出,堆中最大的元素存放在根节点中这种堆被称为大根堆反之被成为小根堆
- 若i=1,其为根结点无父亲结点,否则对任意结点i,其父亲结点都为i/2
- 若2*i>n其没有左孩子,也没有右孩子,否则左孩子编号为 2i;
- 若2*i+1>n,则结点i无右孩子,否则右孩子为2i+1
用堆关键部分是2个操作 put操作既往堆中加入一个元素,get操作,从堆中取出并删除一个元素
- 删除任意一个元素
- 修改任意一个元素
void up(int u) {
while (u >> 1 && h[u >> 1] > h[u]) {
swap(h[u[, h[u >> 1]);
u >>= 1;
}
}
void down(int u) {
int v = u;
if (lc(u) <= idx && h[lc(u)] < h[v]) v = lc(u);
if (rc(u) <= idx && h[rc(u)] < h[v]) v = rc(u);
if (v != u) {
swap(h[u], h[v]);
down(v);
}
}
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e5 + 3;
int h[N], e[N], ne[N], idx;
inline int hash_(int x) {
return ((x % N) + N) % N;
}
void insert(int x) {
int k = hash_(x);
e[idx] = x;
ne[idx] = h[k];
h[k] = idx++;
}
bool query(int x) {
int k = hash_(x);
for (int i = h[k]; i != -1; i = ne[i]) if (e[i] == x) return true;
return false;
}
int main() {
int n, x;
char op;
cin >> n;
memset(h, -1, sizeof(h));
while (n--) {
cin >> op >> x;
if (op == 'I') insert(x);
else cout << (query(x) ? "Yes" : "No") << endl;
}
}
字符串前缀映射成 P 进制数
不能把某个字母映射成0,会导致 "A" == "AA"
#include <iostream>
#include <string>
using namespace std;
typedef unsigned long long ull;
const int N = 1e5 + 10;
ull h[N], p[N];
ull get_hash(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
int main() {
string str;
int n, m;
cin >> n >> m >> str;
p[0] = 1;
for (int i = 1; i <= str.size(); i++) {
p[i] = p[i - 1] * 131;
h[i] = h[i - 1] * 131 + (str[i - 1] - 'A' + 1);
}
int l1, r1, l2, r2;
while (m--) {
cin >> l1 >> r1 >> l2 >> r2;
cout << (get_hash(l1, r1) == get_hash(l2, r2) ? "Yes" : "No") << endl;
}
}