由于两个区间并没有交集,因此如果左区间在查询区间内的话,必然有
L <= mid ,即 L 在左半区间内部
同理,如果要查询右区间的话,必然有 R >= mid + 1 ,即
mid < R ,也就是 R 在右半区间内部
对于查询操作也是同理,理解上面那个这个也就不难了
1 2 3 4 5 6 7 8 9 10
intquery(Node* root, int l, int r, int L, int R) { if (L <= l && r <= R) return root->val; int mid = l + (r - l) / 2, ans = 0; pushDown(root, mid - l + 1, r - mid); if (L <= mid) ans += query(root->left, l, mid, L, R); if (mid < R) ans += query(root->right, mid + 1, r, L, R); return ans; }
//leftnum represents the number of the left sub-interval voidpushDown(Node* root, int leftnum, int rightnum) { if (root->left == nullptr) root->left = newNode(); if (root->right == nullptr) root->right = newNode(); if (root->lazy == 0) return; root->left->val += root->lazy * leftnum; root->right->val += root->lazy * rightnum; root->left->lazy += root->lazy; root->right->lazy += root->lazy; root->lazy = 0; }
/* * root is currently traversed interval, and interval [l, r] is the intervals represented by current node * interval [L, R] is interval ready to be upddate * each element will increase val * * This function should be called like this: update(root, 0, n, L, R, val); * interval [0, n] could be used without an interval [1, n] */ voidupdate(Node* root, int l, int r, int L, int R, int val) { if (L <= l && r <= R) { root->val += (r - l + 1) * val; root->lazy += val; return; } int mid = l + (r - l) / 2; pushDown(root, mid - l + 1, r - mid); if (L <= mid) update(root->left, l, mid, L, R, val); if (mid < R) update(root->right, mid + 1, r, L, R, val); pushUp(root); }
/* * l r L R meaning ibid */ intquery(Node* root, int l, int r, int L, int R) { if (L <= l && r <= R) return root->val; int mid = l + (r - l) / 2, ans = 0; pushDown(root, mid - l + 1, r - mid); if (L <= mid) ans += query(root->left, l, mid, L, R); if (mid < R) ans += query(root->right, mid + 1, r, L, R); return ans; } };
voidinsert(char s[]) { int p = 0; for(int i = 0; s[i]; i ++) { int u = s[i] - 'a'; if(!son[p][u]) son[p][u] = ++idx;//如果当前节点没有以该字符为结尾的节点,那么创建新节点 p = son[p][u];//p进入下一个节点 } cnt[p] ++; }
intquery(char s[])//查询字符串s的出现次数 { int p = 0; for(int i = 0; s[i]; i ++) { int u = s[i] - 'a'; if(!son[p][u]) return0; p = son[p][u]; } return cnt[p]; }
classTrie { private: int N = 1e5; vector<vector<int>>trie;//数组,用于存储各个节点 vector<int>count;//记录某个节点被标记为「某个单词的终点」的次数 int index;//记录目前使用的节点数 public: Trie() { trie.assign(N, vector<int>(26, 0)); count.assign(N, 0); int index = 0; }
voidinsert(string word) { int pos = 0; for (char c : word) { if (trie[pos][c - 'a'] == 0) trie[pos][c - 'a'] = ++index; pos = trie[pos][c - 'a']; } count[pos]++; }
boolsearch(string word) { int pos = 0; for (char c : word) { if (trie[pos][c - 'a'] == 0) returnfalse; pos = trie[pos][c - 'a']; } return count[pos] != 0; }
boolstartsWith(string prefix) { int pos = 0; for (char c : prefix) { if (trie[pos][c - 'a'] == 0) returnfalse; pos = trie[pos][c - 'a']; } returntrue; } };
voidinsert(int x) { int p = 0; for(int i = 30; i >= 0; i --)//如果期望对应数最大,那么我们应当优先保证高位相反,而不是先保证低位相反 { int u = x >> i & 1; if(!son[p][u]) son[p][u] = ++idx; p = son[p][u]; } }
intquery(int x)//尽可能找到一个与 x 异或较大的数(想要异或达到最大,只需要对应位全部相反即可) { int p = 0, ans = 0; for(int i = 30; i >= 0; i --) { int u = x >> i & 1; if(son[p][!u]) ans = 2 * ans + !u, p = son[p][!u]; else ans = 2 * ans + u, p = son[p][u]; } return ans; }
intmain() { int n; cin >> n; int ans = 0; for(int i = 1; i <= n; i ++) { int x; cin >> x; insert(x); ans = max(ans, query(x) ^ x); } cout << ans << endl; return0; }
int tr[N * 32][2], cnt[N * 32], idx;//cnt表示以当前节点为根的子树的个数 int s[N];
int n, m;
voidinsert(int x, int v) { int p = 0; for(int i = 30; i >= 0; i --) { int u = x >> i & 1; if(!tr[p][u]) tr[p][u] = ++idx; p = tr[p][u]; cnt[p] += v; } }
intquery(int x) { int p = 0, ans = 0; for(int i = 30; i >= 0; i --) { int u = x >> i & 1; if(cnt[tr[p][!u]]) ans = 2 * ans + !u, p = tr[p][!u]; else ans = 2 * ans + u, p = tr[p][u]; } return ans; }
intmain() { cin >> n >> m; for(int i = 1; i <= n; i ++) { cin >> s[i]; s[i] ^= s[i - 1]; } insert(s[0], 1); int ans = 0; for(int i = 1; i <= n; i ++) { if(i - m - 1 >= 0) insert(s[i - m - 1], -1);//所需区间为[r - m, r - 1] ans = max(ans, s[i] ^ query(s[i])); insert(s[i], 1);//由于需要取s[i]对应的值,因此插入需要在对ans赋值之后进行 } cout << ans << endl; return0; }
conststaticint N = 2010 * 210; int tr[N][26]; bool isEnd[N]; int idx; string str;
voidadd(string s) { int p = 0; for(char c : s) { int u = c - 'a'; if(tr[p][u] == 0) tr[p][u] = ++idx; p = tr[p][u]; } isEnd[p] = true; }
boolquery(string s, int st, int ed) { int p = 0; for(int i = st; i <= ed; i ++) { char u = s[i] - 'a'; if(tr[p][u] == 0) returnfalse; p = tr[p][u]; } return isEnd[p]; }
boolquery(char letter) { str += letter; int n = str.length(); for(int i = n - 1; i>= max(0, n - 200); i --) { if(query(str, i, n - 1)) returntrue; } returnfalse; } };
/** * Your StreamChecker object will be instantiated and called as such: * StreamChecker* obj = new StreamChecker(words); * bool param_1 = obj->query(letter); */
conststaticint N = 2010 * 210; int tr[N][26]; bool isEnd[N]; int idx; string str;
voidadd(string s) { int p = 0; for(int i = s.length() - 1; i >= 0; i --) { int u = s[i] - 'a'; if(tr[p][u] == 0) tr[p][u] = ++idx; p = tr[p][u]; } isEnd[p] = true; } StreamChecker(vector<string>& words) { memset(tr, 0, sizeof tr); memset(isEnd, false, sizeof isEnd); idx = 0; for(auto s : words) add(s); }
boolquery(char letter) { str += letter; int n = str.length(); int p = 0; for(int i = n - 1; i >= max(0, n - 200); i --) { int u = str[i] - 'a'; if(isEnd[p]) returntrue; if(tr[p][u] == 0) returnfalse; p = tr[p][u]; } return isEnd[p]; } };
/** * Your StreamChecker object will be instantiated and called as such: * StreamChecker* obj = new StreamChecker(words); * bool param_1 = obj->query(letter); */
intmain() { cin >> n >> d; for(int i = 1; i <= n; i ++) { p[i] = i; sz[i] = 1; } int cnt = 0; for(int i = 1; i <= d; i ++) { int x, y; cin >> x >> y; x = find(x), y = find(y); if(x != y) { p[x] = y; sz[y] += sz[x]; } else cnt++;
int tot = 0; for(int j = 1; j <= n; j ++)//记录每个集合当中点的数量 { if(find(j) == j) s[tot++] = sz[j]; } sort(s, s + n, greater<int>()); int sum = 0; for(int k = 0; k < tot && k < cnt + 1; k ++) sum += s[k]; cout << sum - 1 << endl; }
return0; }
哈希表
模板
我们给出两种用数组模拟实现的哈希表模板
线性探测法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
constint N = 1e5 + 10, INF = 0x3f3f3f3f; int h[N];
intfind(int x) { int k = (x % N + N) % N; while(h[k] != INF && h[k] != x) { k++; if(k == N) k = 0; } return k; }
初始化:
1
memset(f, 0x3f, sizeof f);
拉链法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
constint N = 1e5 + 10;
int h[N], e[N], ne[N], idx;
boolfind(int x) { int k = (x % N + N) % N; for(int i = h[x]; i != -1; i = ne[i]) if(e[i] == x) returntrue; returnfalse; }
voidinsert(int x) { int k = (x % N + N) % N; e[idx] = x, ne[idx] = h[k], h[k] = idx++; }
voidadd(int x, int c) { for(int i = x; i <= n; i += lowbit(i)) tr[i] += c; }
intquery(int x) { int ans = 0; for(int i = x; i; i -= lowbit(i)) ans += tr[i]; return ans; }
intmain() { cin >> n >> m; for(int i = 1; i <= n; i ++) cin >> a[i]; for(int i = 1; i <= n; i ++) { int v = a[i] - a[i - 1]; tr[i] = v; for(int j = i - 1; j >= i - lowbit(i) + 1; j -= lowbit(j)) tr[i] += tr[j]; }