###### tags: `CP`
# [CP] 常用的算法 & 結構
### KMP
- 在字串s中,找到所有子串p的位置
- 說明
- 使用時,直接傳入字串s和子串p。
- 所有子字串會在ids裡面找到
- 查看這些id可以用print()
- 程式碼
```=cpp
class KMP_t{
public:
vt<ll> LPS;
vt<ll> ids;
string s,p;
KMP_t(string s, string p){
this->s = s;
this->p = p;
LPS.clear();
ids.clear();
match();
}
void build_FPS(){
ll head = 0;
LPS[0] = 0;
for(ll j = 1; j<p.size(); ++j){
while(head>0 && p[head]!=p[j]){
head = LPS[head-1];
}
if(p[head]==p[j]){
head++;
LPS[j] = head;
}
}
}
void match(){
ll ns = s.size(), np = p.size();
LPS = vt<ll>(np, 0);
build_FPS();
ll i = 0, j = 0;
while(i<ns && j<np){
if(s[i]==p[j]){
j++;
i++;
}
else if(j<=0){
i++;
}
else{
j = LPS[j-1];
}
if(j==np){
ids.push_back(i-np);
j = LPS[j-1];
}
}
}
void print(){
for(auto& e:ids){cout<<e<<" ";}
cout<<endl;
}
};
```
- 時間複雜度:$O(|p|+|s|)$
---
### DSU
- Union Find優化
- 平均常數複雜度 / 每個操作
```cpp
#include "bits/stdc++.h"
#define ll long long
#define vt vector
#define pb push_back
#define fir first
#define sec second
#define mp make_pair
#define endl '\n'
#define double long double
using namespace std;
/*---------------------copy from here---------------------*/
namespace DSU{
class DSU{
public:
vt<ll> p;
vt<ll> sz;
DSU(int N){
p.resize(N);
sz.resize(N);
for(int i = 0; i<N; ++i){p[i] = i;sz[i] = 1;}
}
int find(int x){
if(p[x]==x){return x;}
return p[x] = find(p[x]);
}
void Umerge(int x, int y){
int px = find(x);
int py = find(y);
if(px==py){return;}
if (sz[px] < sz[py])swap(px, py);
p[py] = px;
sz[px]+=sz[py];
}
void merge(int x, int y){
int px = find(x);
int py = find(y);
p[py] = px;
sz[px]+=sz[py];
}
};
}
/*---------------------copy to here---------------------*/
```
---
### Factorial
- Frac數組為階乘
- C為排列組合的$C^n_r$
```cpp
namespace factorial{
const ll mxN = 1e5+1LL, mod = 1e9+7LL;
ll fac[mxN];
void fill_fac(){
fac[0] = fac[1] = 1LL;
for(ll i = 2; i<mxN; ++i){
fac[i] = fac[i-1]*i;
fac[i]%=mod;
}
}
ll C(ll n, ll r){
if(r==0){return 1LL;}
ll v = fac[r]*fac[n-r]%mod;
ll inv_ele = pow(v, mod-2, mod);
return (inv_ele*fac[n])%mod;
}
}
```
---
### Segment tree
- 離散版
- 範例中是區間和,要改其他的可以動`what`函數
```cpp
namespace segtree{
class segtree_node {
public:
ll s = -1, e = -1, val = 1e9 + 1;
segtree_node* left = nullptr,* right = nullptr;
segtree_node(ll val, ll s, ll e) {
this->val = val;
this->s = s, this->e = e;
}
segtree_node(ll val, ll s, ll e, segtree_node* left, segtree_node* right) {
this->val = val;
this->s = s, this->e = e;
this->left = left, this->right = right;
}
};
ll what(ll x, ll y) {
return x + y;
}
segtree_node* build_segtree(ll s, ll e, const vt<ll>& a) {
//check({ s, e });
if (s == e) {
segtree_node* new_node = new segtree_node(a[s], s, s);
return new_node;
}
ll mid = (s + e) >> 1;
segtree_node* left = build_segtree(s, mid, a);
segtree_node* right = build_segtree(mid + 1, e, a);
segtree_node* root = new segtree_node(what(left->val, right->val), s, e, left, right);
return root;
}
void update_segtree(segtree_node* root, ll id, ll val, const vt<ll>& a) { // a is useless
if (root->s == root->e && root->s == id) {
root->val = val;
return;
}
ll mid = (root->s + root->e) >> 1;
if (id <= mid) {
update_segtree(root->left, id, val, a);
}
else if (id > mid) {
update_segtree(root->right, id, val, a);
}
root->val = what(root->left->val, root->right->val);
}
ll query_sum(segtree_node* root, ll L, ll R) {
if (root->s == L && root->e == R) { return root->val; }
ll mid = (root->s + root->e) >> 1;
//check({ root->s, root->e, mid,L, R });
if (L > mid) { //the range is totally at root->right
return query_sum(root->right, L, R);
}
else if (R <= mid) {//the range is totally at root->left
return query_sum(root->left, L, R);
}
else {
return what(query_sum(root->left, L, mid), query_sum(root->right, mid + 1, R));
}
}
}
int main() {
}
```