模板复习

本文深入解析了多种经典算法模板,包括KMP字符串匹配、线段树区间查询与更新、树链剖分、平衡树操作、最大流及最小费用最大流算法。通过详细代码示例,阐述了每种算法的核心思想与实现细节,为读者提供了丰富的学习资源。
摘要由CSDN通过智能技术生成

Hihocoder KMP

#include<bits/stdc++.h>
#define reg register

const int maxn = 1000005;

char s[maxn], T[maxn];
int len_s, len_t, cnt, N;
int nxt[maxn];

void Getnxt(){
        nxt[0] = -1;
        int i = 0, t = -1;
        while(i < len_s)
                if(t == -1 || s[i] == s[t]) nxt[++ i] = ++ t; //  "==" --> "!="
                else t = nxt[t];
}

void KMP(){
        int t1 = 0, t2 = 0;
        while(t2 < len_t)
                if(t1 == -1 || s[t1] == t[t2]){
                        t1 ++, t2 ++; 
                        if(t1 == len_s){ 
                                t1 = nxt[t1]; 
                                cnt ++;
                        }
                }else t1 = nxt[t1];
}

void Work(){
        scanf("%s%s", s, T);
        len_s = strlen(s), len_t = strlen(T);
        Getnxt();
        cnt = 0;
        KMP();
        printf("%d\n", cnt);
}

int main(){
        scanf("%d", &N);
        while(N --) Work();
        return 0;
}

Hihocoder #1077 : RMQ问题再临-线段树 线段树单点修改, 区间最小值

#include<bits/stdc++.h>
#define reg register

const int maxn = 1e6 + 10;

int N, M;
int Ql, Qr;

struct Node{
        int v, l, r, min_v;
} T[maxn<<2];

void Build(int k, int l, int r){
        T[k].l = l, T[k].r = r;
        if(l == r){
                scanf("%d", &T[k].v), T[k].min_v = T[k].v;
                return ;
        }
        int mid = l+r >> 1;
        Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
        T[k].min_v = std::min(T[k<<1].min_v, T[k<<1|1].min_v);
}

int Query(int k){
        int l = T[k].l, r = T[k].r;
        if(Ql <= l && r <= Qr) return T[k].min_v;
        int mid = l+r >> 1;
        if(mid < Ql) return Query(k<<1|1);
        else if(mid >= Qr) return Query(k<<1);
        return std::min(Query(k<<1|1), Query(k<<1));
}

void Modify(int k){
        int l = T[k].l, r = T[k].r;
        if(l == r){
                T[k].min_v = T[k].v = Qr;
                return ;
        }
        int mid = l+r >> 1;
        if(Ql <= mid) Modify(k<<1);
        else Modify(k<<1|1);
        T[k].min_v = std::min(T[k<<1].min_v, T[k<<1|1].min_v);
}

int main(){
        scanf("%d", &N);
        Build(1, 1, N);
        scanf("%d", &M);
        int opt;
        while(M --){
                scanf("%d%d%d", &opt, &Ql, &Qr);
                if(!opt){
                        int Ans = Query(1);
                        printf("%d\n", Ans);
                }
                else Modify(1);
        }
        return 0;
}

P3372 【模板】线段树 1线段树区间修改, 区间和

注意标记的加值

#include<bits/stdc++.h>
#define reg register

const int maxn = 1e6 + 10;

typedef long long ll;

int N, M;
int Ql, Qr;
ll Qv;
int tag[maxn<<2];

struct Node{
        ll v, min_v, sum;
        int l, r;
} T[maxn<<2];

void Build(int k, int l, int r){
        T[k].l = l, T[k].r = r;
        if(l == r){
                scanf("%lld", &T[k].v), T[k].min_v = T[k].v, T[k].sum = T[k].v;
                return ;
        }
        int mid = l+r >> 1;
        Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
        T[k].min_v = std::min(T[k<<1].min_v, T[k<<1|1].min_v);
        T[k].sum = T[k<<1].sum + T[k<<1|1].sum;
}

void Push_down(int k){
        int l, r;
        tag[k<<1] += tag[k], tag[k<<1|1] += tag[k];
        l = T[k<<1].l, r = T[k<<1].r;
        T[k<<1].sum += 1ll*(r - l + 1) * tag[k];
        l = T[k<<1|1].l, r = T[k<<1|1].r;
        T[k<<1|1].sum += 1ll*(r - l + 1) * tag[k];
        tag[k] = 0;
}

void Modify_2(int k){
        int l = T[k].l, r = T[k].r;
        if(Ql <= l && r <= Qr){
                T[k].sum += 1ll*(r-l+1)*Qv;
                tag[k] += Qv;
                return ;
        }
        if(tag[k]) Push_down(k);
        int mid = l+r >> 1;
        if(mid < Ql) Modify_2(k<<1|1);
        else if(mid >= Qr) Modify_2(k<<1);
        else Modify_2(k<<1), Modify_2(k<<1|1);
        T[k].sum = T[k<<1].sum + T[k<<1|1].sum;
}

ll Query_2(int k){
        int l = T[k].l, r = T[k].r;
        if(Ql <= l && r <= Qr) return T[k].sum;
        if(tag[k]) Push_down(k);
        ll tmp = 0;
        int mid = l+r >> 1;
        if(mid < Ql) tmp += Query_2(k<<1|1);
        else if(mid >= Qr) tmp += Query_2(k<<1);
        else tmp += Query_2(k<<1) + Query_2(k<<1|1);
        T[k].sum = T[k<<1].sum + T[k<<1|1].sum;
        return tmp;
}

int main(){
        scanf("%d%d", &N, &M);
        Build(1, 1, N);
        int opt;
        while(M --){
                scanf("%d%d%d", &opt, &Ql, &Qr);
                if(opt == 1){
                        scanf("%lld", &Qv);
                        Modify_2(1);
                }else{
                        ll Ans = Query_2(1);
                        printf("%lld\n", Ans);
                }
        }
        return 0;
}

树链剖分

注意Dfn序和原编号的区别

#include<bits/stdc++.h>
#define reg register

const int maxn = 1e5+10;

int N, M, R, P;
int head[maxn], size[maxn], max_son[maxn], max_w[maxn];
int top[maxn], dfn[maxn], Fa[maxn], dep[maxn], w[maxn], max_num[maxn];
int tim, num0;

namespace Seg{

        struct Node{
                int v, l, r, tag;
        } T[maxn<<2];

        void Build(int k, int l, int r){
                T[k].l = l, T[k].r = r;
                if(l == r){
                        T[k].v = T[k].tag = 0;
                        return ;
                }
                int mid = l+r >> 1;
                Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
                T[k].v = (1ll*T[k<<1].v + T[k<<1|1].v) % P;
        }

        void Push_down(int k){
                T[k<<1].tag = (1ll*T[k<<1].tag + T[k].tag) % P;
                T[k<<1|1].tag = (1ll*T[k<<1|1].tag + T[k].tag) % P;
                int l, r;
                l = T[k<<1].l, r = T[k<<1].r;
                T[k<<1].v = (1ll*T[k<<1].v + (1ll*T[k].tag*(r - l + 1) % P)) % P;
                l = T[k<<1|1].l, r = T[k<<1|1].r;
                T[k<<1|1].v = (1ll*T[k<<1|1].v + (1ll*T[k].tag*(r - l + 1) % P)) % P;
                T[k].tag = 0;
        }

        void Modify(int k, const int &Ql, const int &Qr, const int &v){
                int l = T[k].l, r = T[k].r;
                if(Ql <= l && r <= Qr){
                        T[k].v += 1ll*v*(r - l + 1) % P;
                        T[k].tag = (1ll*T[k].tag + v) % P;
                        return ;
                }
                if(T[k].tag) Push_down(k);
                int mid = l+r >> 1;
                if(mid < Ql) Modify(k<<1|1, Ql, Qr, v);
                else if(mid >= Qr) Modify(k<<1, Ql, Qr, v);
                else Modify(k<<1, Ql, Qr, v), Modify(k<<1|1, Ql, Qr, v);
                T[k].v = (1ll*T[k<<1].v + T[k<<1|1].v) % P;
        }

        int Query(int k, const int &Ql, const int &Qr){
                int l = T[k].l, r = T[k].r;
                if(Ql <= l && r <= Qr) return T[k].v;
                if(T[k].tag) Push_down(k);
                int mid = l+r >> 1;
                T[k].v = (1ll*T[k<<1].v + T[k<<1|1].v) % P;
                if(mid < Ql) return Query(k<<1|1, Ql, Qr);
                else if(mid >= Qr) return Query(k<<1, Ql, Qr);
                return (1ll*Query(k<<1|1, Ql, Qr) + Query(k<<1, Ql, Qr)) % P;
        }

}

struct Edge{ int nxt, to; } edge[maxn<<1];

void Add(int from, int to){
        edge[++ num0] = (Edge){ head[from], to };
        head[from] = num0;
}

void DFS_1(int k, int fa){
        size[k] = 1;
        max_son[k] = 0, max_w[k] = 0;
        dep[k] = dep[fa] + 1;
        Fa[k] = fa;
        for(reg int i = head[k]; i; i = edge[i].nxt){
                int to = edge[i].to;
                if(to == fa) continue ;
                DFS_1(to, k);
                size[k] += size[to];
                if(size[to] > max_w[k]){
                        max_w[k] = size[to];
                        max_son[k] = to;
                }
        }
}

void DFS_2(int k, int fa){
        dfn[k] = ++ tim;
        Seg::Modify(1, dfn[k], dfn[k], w[k]);
        top[k] = fa;
        if(max_son[k]) DFS_2(max_son[k], fa);
        for(reg int i = head[k]; i; i = edge[i].nxt){
                int to = edge[i].to;
                if(dfn[to]) continue ;
                DFS_2(to, to);
        }
        max_num[k] = tim;
}

void Modify_P(int x, int y, int z){
        while(top[x] != top[y]){
                if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
                Seg::Modify(1, dfn[top[x]], dfn[x], z);
                x = Fa[top[x]];
        }
        if(dfn[x] > dfn[y]) std::swap(x, y);
        Seg::Modify(1, dfn[x], dfn[y], z);
}

int Query_P(int x, int y){
        int res = 0;
        while(top[x] != top[y]){
                if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
                res = (1ll*res+Seg::Query(1, dfn[top[x]], dfn[x])) % P;
                x = Fa[top[x]];
        }
        if(dfn[x] > dfn[y]) std::swap(x, y);
        res = (1l*res + Seg::Query(1, dfn[x], dfn[y])) % P;
        return res;
}

void Work(){
        int opt, x, y, z;
        scanf("%d", &opt);
        if(opt == 1){
                scanf("%d%d%d", &x, &y, &z);
                Modify_P(x, y, z);
        }else if(opt == 2){
                scanf("%d%d", &x, &y);
                int Ans = Query_P(x, y);
                printf("%d\n", Ans);
        }else if(opt == 3){
                scanf("%d%d", &x, &z);
                Seg::Modify(1, dfn[x], max_num[x], z);
        }else{
                scanf("%d", &x);
                int Ans = Seg::Query(1, dfn[x], max_num[x]);
                printf("%d\n", Ans);
        }
}

int main(){
        scanf("%d%d%d%d", &N, &M, &R, &P);
        int a, b;
        for(reg int i = 1; i <= N; i ++) scanf("%d", &w[i]);
        Seg::Build(1, 1, N);
        for(reg int i = 1; i < N; i ++){
                scanf("%d%d", &a, &b);
                Add(a, b), Add(b, a);
        }
        DFS_1(R, R);            // second  'R' --> '0'
        DFS_2(R, R);            // second  'R' --> '0'
        while(M --) Work();
        return 0;
}

普通平衡树

> 和 < 的区别
5个数组
对一个节点进行操作后进行Splay
前驱后继的操作注意特判 ↓ ↓

int S_pre(int x, short opt){  // 1: su  0:  pre
        find(x);
        if(opt == 1){	//特判
                if(key[rot] > x) return rot;
        }else if(key[rot] < x) return rot;
        int t = ch[rot][opt]; opt ^= 1;
        while(ch[t][opt]) t = ch[t][opt];
        return t;
}

插入的时候必须Splay
注意赋值关系 ↓ ↓

//AC
int Kth(int t, int x){
        while(1){
                if(ch[t][0] && size[ch[t][0]] >= x) t = ch[t][0]; 
                else if(size[ch[t][0]] + cnt[t] < x) x -= size[ch[t][0]] + cnt[t], t = ch[t][1];
                else return t;
        }
}
//WA

int Kth(int t, int x){
        while(1){
                if(ch[t][0] && size[ch[t][0]] >= x) t = ch[t][0]; 
                else if(size[ch[t][0]] + cnt[t] < x)  t = ch[t][1], x -= size[ch[t][0]] + cnt[t];
                else return t;
        }
}
#include<bits/stdc++.h>
#define reg register

const int maxn = 100005;

int num0, rot;
int cnt[maxn], size[maxn];
int par[maxn], ch[maxn][2], key[maxn];

inline void Push_up(int x){ size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; }

inline bool chk(int x){ return ch[par[x]][1] == x; }

void rotate(int x){
        int y = par[x], z = par[y], d = chk(x), s = ch[x][d^1];
        ch[y][d] = s, par[s] = y;
        ch[z][chk(y)] = x, par[x] = z;
        ch[x][d^1] = y, par[y] = x;
        Push_up(y), Push_up(x);
}

void Splay(int x, int aim=0){
        while(par[x] != aim){
                int y = par[x], z = par[y];
                if(z != aim){
                        if(chk(x) == chk(y)) rotate(y);
                        else rotate(x);
                }
                rotate(x);
        }
        if(!aim) rot = x;
}

void Insert(int x){ //~~
        int t = rot, last = 0;
        while(t && key[t] != x){
                last = t;
                t = ch[t][key[t] < x];
        }
        if(t) cnt[t] ++;
        else{
                key[t = ++ num0] = x;
                if(last) ch[last][key[last] < x] = num0;
                ch[num0][0] = ch[num0][1] = 0, size[num0] = 1;
                par[num0] = last;
                cnt[num0] = 1;
        }
        Splay(t);
}

void find(int x){
        if(!rot) return ;
        int t = rot;
        while(ch[t][key[t] < x] && key[t] != x) t = ch[t][key[t] < x];
        Splay(t);
}

int S_pre(int x, short opt){  // 1: su  0:  pre
        find(x);
        
        if(opt == 1){
                if(key[rot] > x) return rot;
        }else if(key[rot] < x) return rot;
        
        int t = ch[rot][opt]; opt ^= 1;
        while(ch[t][opt]) t = ch[t][opt];
        return t;
}

void Remove(int x){
        int su = S_pre(x, 1), pre = S_pre(x, 0);
        Splay(pre), Splay(su, pre);
        int t = ch[su][0];
        if(cnt[t] == 1) ch[su][0] = 0;
        else cnt[t] --, Splay(t);   //~~
}

inline void Ask_1(int x){
        find(x);
        printf("%d\n", size[ch[rot][0]]);
}

int Kth(int t, int x){
        while(1){
                if(ch[t][0] && size[ch[t][0]] >= x) t = ch[t][0]; 
                else if(size[ch[t][0]] + cnt[t] < x) x -= size[ch[t][0]] + cnt[t], t = ch[t][1];
                else return t;
        }
}

inline void Ask_2(int x){
//        printf("fuck: %d size: %d cnt %d\n",rot, size[ch[rot][0]], cnt[rot]);  
        int t = Kth(rot, x);
        printf("%d\n", key[t]);
}

void Work(){
        int opt, x;
        scanf("%d%d", &opt, &x);
        if(opt == 1) Insert(x);
        else if(opt == 2) Remove(x);
        else if(opt == 3) Ask_1(x);
        else if(opt == 4) Ask_2(x+1);
        else if(opt == 5) printf("%d\n", key[S_pre(x, 0)]);
        else printf("%d\n", key[S_pre(x, 1)]);
}

int main(){
        int N;
        scanf("%d", &N);
        Insert(0xcfcfcfcf), Insert(0x3f3f3f3f);
        for(reg int i = 1; i <= N; i ++) Work();
        return 0;
}

最大流

#include<bits/stdc++.h>
#define reg register

const int maxn = 100005;
const int inf = 0x7f7f7f7f;

int N, M, S, T, num0;
int head[maxn], cur[maxn], dep[maxn];

struct Edge{
        int nxt, to, dis, flow;
} edge[maxn<<1];

void Add(int from, int to, int Dis){
        edge[num0] = (Edge){ head[from], to, Dis, 0 };
        head[from] = num0 ++;
}

bool BFS(){
        memset(dep, -1, sizeof dep);
        for(reg int i = 0; i <= N; i ++) cur[i] = head[i];
        dep[S] = 1;
        std::queue <int> Q;
        Q.push(S);
        while(!Q.empty()){
                int t = Q.front(); Q.pop();
                for(reg int i = head[t]; ~i; i = edge[i].nxt){
                        int to = edge[i].to;
                        if(dep[to] == -1 && edge[i].dis > edge[i].flow){
                                dep[to] = dep[t] + 1;
                                Q.push(to);
                        }
                }
        }
        return dep[T] != -1;
}

int DFS(int k, int W){
        if(k == T) return W;
        for(reg int &i = cur[k]; ~i; i = edge[i].nxt){
                int to = edge[i].to;
                if(dep[to] == dep[k] + 1 && edge[i].dis > edge[i].flow){
                        int tmp = DFS(to, std::min(W, edge[i].dis - edge[i].flow));
                        if(tmp){
                                edge[i].flow += tmp;
                                edge[i^1].flow -= tmp;
                                return tmp;
                        }
                }
        }
        return 0;
}

int Dinic(){
        int Ans = 0;
        while(BFS()){
                while(int res = DFS(S, inf)) Ans += res;
        }
        return Ans;
}

int main(){
        scanf("%d%d%d%d", &N, &M, &S, &T);
        int x, y, z;
        memset(head, -1, sizeof head);
        for(reg int i = 1; i <= M; i ++){
                scanf("%d%d%d", &x, &y, &z);
                Add(x, y, z), Add(y, x, 0);
        }
        printf("%d\n", Dinic());
        return 0;
}
/*
memset(head, -1, sizeof head)

void Add(int from, int to, int Dis){
        edge[num0] = (Edge){ head[from], to, Dis, 0 };
        head[from] = num0 ++;
}

*/

最小费用最大流

#include<bits/stdc++.h>
#define reg register

const int maxn = 50005;

int N, M, S, T, num0;
int head[maxn];
std::bitset <5005> Used;
int Dis[5005], Flow[5005], Pre[5005], Pre_1[5005];

struct Edge{
        int nxt, to, dis, flow, cost;
} edge[maxn << 1];

void Add(int from, int to, int dis, int cost){
        edge[num0] = (Edge){ head[from], to, dis, 0, cost };
        head[from] = num0 ++;
}

int Spfa(){
        memset(Dis, 0x3f, sizeof Dis);
        memset(Flow, 0x3f, sizeof Flow);
        Used.reset();
        std::queue <int> Q;
        Q.push(S), Dis[S] = 0, Used.set(S, 1);
        while(!Q.empty()){
                int t = Q.front(); Q.pop();
                //printf("fuck %d\n", t);
                Used.set(t, 0);
                for(reg int i = head[t]; ~i; i = edge[i].nxt){
                        int to = edge[i].to;
                        if(Dis[to] > Dis[t] + edge[i].cost && edge[i].dis > edge[i].flow){
                                Dis[to] = Dis[t] + edge[i].cost;
                                Pre[to] = t;
                                Pre_1[to] = i;
                                Flow[to] = std::min(Flow[t], edge[i].dis - edge[i].flow);
                                if(!Used.test(to)){
                                        Used.set(to, 1); Q.push(to);
                                }
                        }
                }
        }
        return Flow[T];
}

int MFMS(){
        int Ans = 0, res = 0, Ans_2 = 0;
        while((res = Spfa()) != 0x3f3f3f3f){
                Ans += res;
                Ans_2 += Dis[T] * Flow[T];
                int t = T;
                while(t != S){
                        int tmp = Pre_1[t];
                        edge[tmp].flow += res;
                        edge[tmp^1].flow -= res;
                        t = Pre[t];
                }
        }
        printf("%d ", Ans);
        return Ans_2;
}

int main(){
//        freopen("test.in", "r", stdin);
        scanf("%d%d%d%d", &N, &M, &S, &T);
        memset(head, -1, sizeof head);
        for(reg int i = 1; i <= M; i ++){
                int x, y, z, w;
                scanf("%d%d%d%d", &x, &y, &z, &w);
                Add(x, y, z, w), Add(y, x, 0, -w);
        }
        printf("%d\n", MFMS());
        return 0;
}
/*
Add(x, y, z, w), Add(y, x, 0, -w);

if(Dis[to] > Dis[t] + edge[i].cost && edge[i].dis > edge[i].flow){
        
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值