退役划水二 诈尸记录(春季赛前打打板子)

图论

存图

链式前向星

$Code$
struct Graph{
    int cnt;
    int head[MAXN];

    Graph(){
        cnt = 0;
        memset(head, 0, sizeof(head));
    }

    struct Edge{
        int to, next, dis;
    }e[MAXN];

    inline void Add(int u, int v, int w){
        e[++cnt].to = v;
        e[cnt].dis = w;
        e[cnt].next = head[u];
        head[u] = cnt;
    }
}G;

最短路

\(\mathit{Floyed}\)

$Code$
void Floyed(){
    for(register int k = 1; k <= n; k++){
        for(register int i = 1; i <= n; i++){
            for(register int j = 1; j <= n; j++){
                if(k == i || k == j || i == j) continue;
                if(map[i][j] > map[i][k] + map[k][j]) map[i][j] = map[i][k] + map[k][j];
            }
        }
    }
}

\(\mathit{SPFA}\)

$Code$
void Spfa(int u){
    queue<int> q;
    memset(dis, 0x3f, sizeof(dis));

    q.push(u), dis[u] = 0, vis[u] = true;
    while(!q.empty()){
        int t = q.front();
        for(register int i = G.head[t]; i; i = G.e[i].next){
            int v = G.e[i].to;
            if(dis[v] > dis[t] + G.e[i].dis){
                dis[v] = dis[t] + G.e[i].dis;
                if(!vis[v]) q.push(v), vis[v] = true;
            }
        }
        vis[t] = false;
        q.pop();
    }
}

堆优化 \(\mathit{Dijkstra}\)

$Code$
struct Road{
    int pos, dis;

    bool operator < (const Road &a) const{
        return dis > a.dis;
    }
};

priority_queue< Road, vector<Road>, greater<Road> > q;

void Dijkstra(int u){
    memset(dis, 0x3f, sizeof(dis));

    dis[u] = 0, q.push((Road){u, 0});
    while(!q.empty()){
        int t = q.top().pos;
        q.pop();

        if(vis[t]) continue;
        vis[t] = true;
        for(register int i = G.head[t]; i; i = G.e[i].next){
            int v = G.e[i].to;
            if(dis[v] > dis[t] + G.e[i].dis){
                dis[v] = dis[t] + G.e[i].dis;
                if(!vis[v]) q.push((Road){v, dis[v]});
            }
        }
    }
}

最小生成树

\(\mathit{Prim}\) 算法

$Code$
struct Road{
    int pos, dis;

    bool operator < (const Road &a) const{
        return dis > a.dis;
    }
};

priority_queue< Road, vector<Road>, greater<Road> > q;

void Prim(){
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0;
    q.push((Road){1, dis[1]});

    while(!q.empty() && tot < n){
        int k = q.top().pos;
        q.pop();

        if(used[k]) continue;
        tot++;
        sum += dis[k];
        used[k] = true;
        for(register int i = head[k]; i; i = e[i].next){
            int v = e[i].to;
            if(dis[v] > e[i].dis){
                dis[v] = e[i].dis;
                q.push((Road){v, dis[v]}); 
            }
        }
    }
}

\(\mathit{Kruskal}\) 算法

$Code$
struct Line{
    int from, to, dis;
}line[MAXM];

bool cmp(const Line &a, const Line &b){
    return a.dis < b.dis;
}

struct Union_Set{
    int fa[MAXN];

    void init(int n){
        for(register int i = 1; i <= n; i++) fa[i] = i;
    }

    int Find(int x){
        return fa[x] == x ? x : fa[x] = Find(fa[x]);
    }
}U;

void Kruskal(){
    U.init(n);
    sort(line + 1, line + 1 + m, cmp);

    for(register int i = 1; i <= m; i++){
        int u = line[i].from, v = line[i].to;
        int fa_u = U.Find(u), fa_v = U.Find(v);
        if(fa_u != fa_v){
            ++tot;
            U.fa[fa_u] = fa_v;
            G.Add(u, v, line[i].dis), G.Add(v, u, line[i].dis);
        }
        if(tot == n - 1) break;
    } 
}

\(\mathit{Tarjan}\)

求强连通分量及缩点

$Code$
void Tarjan(int u){
    low[u] = dfn[u] = ++num;
    vis[u] = true;
    stk[++top] = u;

    for(register int i = G.head[u]; i; i = G.e[i].next){
        int v = G.e[i].to;
        if(!dfn[v]){
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }

    if(low[u] == dfn[v]){
        ++tot; int t;
        do{
            t = stk[top--];
            vis[t] = false;
            belong[t] = tot;
        }while(t != u);
    }
}

void Rebuild(){
    G.cnt = 0;
    memset(G.head, 0, sizeof(G.head));

    for(register int i = 1; i <= m; i++){
        int u = from[i], v = to[i];
        if(belong[u] != belong[v]) G.Add(u, v);
    }
}

求割点

$Code$
void Tarjan(int u){
    dfn[u] = low[u] = ++num;
    int son = 0;
    for(register int i = G.head[u]; i; i = G.e[i].next){
        int v = G.e[i].to;
        if(!dfn[v]){
            ++son;
            Tarjan(v);
            low[u] = min(low[u], low[v]);
            if(dfn[u] <= low[v]){
                if(son > 1 || u != root) cut[u] = true;
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}

求点双联通分量

$Code$
void Tarjan(int u, int fa){
    dfn[u] = low[u] = ++num;
    vis[u] = true, stk[++top] = u;
    int son = 0; bool first = true;

    for(register int i = G.head[u]; i; i = G.e[i].next){
        int v = G.e[i].to;
        if(first && v == fa){
            first = false;
            continue;
        }
        if(!dfn[v]){
            ++son;
            Tarjan(v, u);
            low[u] = min(low[u], low[v]);

            if(dfn[u] <= low[v]){
                cut[u] = true;
                ++tot;
                point[tot].push_back(u);
                int t;
                do{
                    t = stk[top--];
                    point[tot].push_back(u);
                }while(t != u);
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }

    if(!fa && son == 1) cut[u] = false;
}

二分图

匈牙利算法

$Code$
bool dfs(int u){
    for(register int i = G.head[u]; i; i = G.e[i].next){
        int v = G.e[i].to;
        if(!vis[v]){
            vis[v] = true;
            if(!match[v] || dfs(match[v])){
                match[v] = u;
                return true;
            }
        }
    }

    return false;
}

int Hungary(){
    int ans = 0;

    for(register int i = 1; i <= n; i++){
        memset(vis, 0, sizeof(vis));
        if(dfs(i)) ++ans;
    }

    return ans;
}

\(\mathit{Kruskal}\) 重构树

$Code$
struct Line{
    int from, to, dis;
}line[MAXM];

bool cmp(const Line &a, const Line &b){
    return a.dis < b.dis;
}

struct Union_Set{
    int fa[MAXN];

    void init(int n){
        for(register int i = 1; i <= n; i++) fa[i] = i;
    }

    int Find(int x){
        return fa[x] == x ? x : fa[x] = Find(fa[x]);
    }
}U;

void Kruskal(){
    int tot = 0; sum = n, G.cnt = 0;
    memset(G.head, 0, sizeof(G.head));

    U.init(n << 1);
    sort(line + 1, line + 1 + m, cmp);

    for(register int i = 1; i <= m; i++){
        int u = line[i].from, v = line[i].to;
        int fa_u = U.Find(u), fa_v = U.Find(v);

        if(fa_u != fa_v){
            ++tot;
            val[++sum] = line[i].dis;
            G.Add(fa_u, sum), G.Add(sum, fa_u);
            G.Add(fa_v, sum), G.Add(sum, fa_v);
            U.fa[fa_u] = U.fa[fa_v] = sum;
        }
        if(tot == n - 1) break;
    }
}

字符串

哈希

不用写。

\(\mathit{KMP}\) 算法

不会真有人到退役也搞不清楚 \(KMP\) 吧,不会吧不会吧。😋

\(\mathit{Trie}\)

字典树

$Code$
struct Trie{
    int sz;
    bool val[MAXN];
    int ch[MAXN][SIZE];

    Trie(){
        sz = 0;
        memset(ch, 0, sizeof(ch));
        memset(val, 0, sizeof(val));
    }

    void Insert(char *s){
        int u = 0, len = strlen(s + 1);
        for(register int i = 1; i <= len; i++){
            int v = s[i] - 'a';
            if(!ch[u][v]) ch[u][v] = ++sz;
            u = ch[u][v];
        }
        val[u] = true;
    }

    bool Search(char *s){
        int u = 0, len = strlen(s + 1);
        for(register int i = 1; i <= len; i++){
            int v = s[i] - 'a';
            if(!ch[u][v]) return false;
            u = ch[u][v];
        }
        if(val[u]) return true;
        else return false;
    }
}T;

\(01Trie\)

$Code$
struct Trie{
    int sz;
    bool val[MAXN];
    int ch[MAXN][2];

    Trie(){
        sz = 0;
        memset(ch, 0, sizeof(ch));
        memset(val, 0, sizeof(val));
    }

    void Insert(int num){
        int u = 0;
        for(register int i = 31; i >= 0; i--){
            int v = (num >> i) & 1;
            if(!ch[u][v]) ch[u][v] = ++sz;
            u = ch[u][v];
        }
        val[u] = true;
    }

    int Search(int num){
        int u = 0, ans = 0;
        for(register int i = 31; i >= 0; i--){
            int v = (num >> i) & 1;
            if(ch[u][v ^ 1]) ans += 1 << i, u = ch[u][v ^ 1];
            else u = ch[u][v];
        }

        return ans;
    }
}T;

\(\mathit{AC}\) 自动机

树论

树链剖分

$Code$
struct Graph{
    int cnt;
    int head[MAXN];

    struct Edge{
        int to, next;
    }e[MAXN << 1];

    void Add(int u, int v){
        e[++cnt].to = v;
        e[cnt].next = head[u];
        head[u] = cnt;
    }
}G;

void dfs_deep(int rt, int father, int depth){
    size[rt] = 1, fa[rt] = father, deep[rt] = depth;

    int max_son = -1;
    for(register int i = G.head[rt]; i; i = G.e[i].next){
        int v = G.e[i].to;
        if(v == father) continue;

        dfs_deep(v, rt, depth + 1);
        size[rt] += size[v];
        if(size[v] > max_son) son[rt] = v, max_son = size[v];
    }
}

void dfs_top(int rt, int top_fa){
    dfn[rt] = ++num, top[rt] = top_fa, val[num] = data[rt];
    if(!son[rt]) return;

    dfs_top(son[rt], top_fa);

    for(register int i = G.head[rt]; i; i = G.e[i].next){
        int v = G.e[i].to;
        if(!dfn[v]) dfs_top(v, v);
    }
}

struct Segment_Tree{
    struct Tree{
        int l, r;
        LL sum;
        LL lazy;
    }tr[MAXN << 2];

    inline int lson(int rt){
        return rt << 1;
    }

    inline int rson(int rt){
        return rt << 1 | 1;
    }

    inline void Pushup(int rt){
        tr[rt].sum = 1LL * (tr[lson(rt)].sum + tr[rson(rt)].sum) % p;
    }

    void Build(int rt, int l, int r){
        tr[rt].l = l, tr[rt].r = r;
        if(l == r){
            tr[rt].sum = val[l] % p;
            return;
        }

        int mid = (l + r) >> 1;
        Build(lson(rt), l, mid);
        Build(rson(rt), mid + 1, r);

        Pushup(rt);
    }

    inline void Pushdown(int rt){
        if(tr[rt].lazy){
            tr[lson(rt)].lazy = 1LL * (tr[lson(rt)].lazy + tr[rt].lazy) % p;
            tr[rson(rt)].lazy = 1LL * (tr[rson(rt)].lazy + tr[rt].lazy) % p;
            tr[lson(rt)].sum = 1LL * (tr[lson(rt)].sum + (tr[lson(rt)].r - tr[lson(rt)].l + 1) % p * tr[rt].lazy % p) % p;
            tr[rson(rt)].sum = 1LL * (tr[rson(rt)].sum + (tr[rson(rt)].r - tr[rson(rt)].l + 1) % p * tr[rt].lazy % p) % p;
            tr[rt].lazy = 0;
        }
    }

    void Update_Add(int rt, int l, int r, int data){
        if(tr[rt].l >= l && tr[rt].r <= r){
            tr[rt].lazy = 1LL * (tr[rt].lazy + data) % p;
            tr[rt].sum = 1LL * (tr[rt].sum + (tr[rt].r - tr[rt].l + 1) % p * data % p) % p;
            return;
        }

        Pushdown(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Add(lson(rt), l, r, data);
        if(r > mid) Update_Add(rson(rt), l, r, data);

        Pushup(rt);
    }

    LL Query_Sum(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].sum;

        Pushdown(rt);

        LL ans = 0;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = 1LL * (ans + Query_Sum(lson(rt), l, r)) % p;
        if(r > mid) ans = 1LL * (ans + Query_Sum(rson(rt), l, r)) % p;

        return ans;
    }
}S;

void Update_Tree_Add(int x, int y, int data){
    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        S.Update_Add(1, dfn[top[x]], dfn[x], data);
        x = fa[top[x]];
    }
    if(deep[x] > deep[y]) swap(x, y);
    S.Update_Add(1, dfn[x], dfn[y], data);
}

LL Query_Tree_Sum(int x, int y){
    LL ans = 0;

    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x, y);
        ans = 1LL * (ans + S.Query_Sum(1, dfn[top[x]], dfn[x])) % p;
        x = fa[top[x]];
    }
    if(deep[x] > deep[y]) swap(x, y);
    ans = 1LL * (ans + S.Query_Sum(1, dfn[x], dfn[y])) % p;

    return ans;
}
posted @ 2023-02-20 21:37  TSTYFST  阅读(76)  评论(4编辑  收藏  举报