板子汇总

可持久化线段树

例题

struct Persistent_Segment_Tree
{
    struct Point
    {
        int l, r;
        LL sum;
    }p[N * 25];
    int rt[N], cnt = 0;
    
    void Newpoint(int &rt, int last, int l, int r, int x, int v)
    {
        rt = ++cnt;
        p[rt] = p[last], p[rt].sum += v;
        if (l == r) return;
        int mid = l + r >> 1;
        if (x <= mid) Newpoint(p[rt].l, p[last].l, l, mid, x, v);
        else Newpoint(p[rt].r, p[last].r, mid + 1, r, x, v);
    }

    LL Query(int rt_1, int rt_2, int l, int r, int x, int y)
    {
        if(x <= l && y >= r)
            return p[rt_2].sum - p[rt_1].sum;
        LL res = 0;
        int mid = l + r >> 1;
        if (x <= mid)
            res += Query(p[rt_1].l, p[rt_2].l, l, mid, x, y);
        if (y >= mid + 1)
            res += Query(p[rt_1].r, p[rt_2].r, mid + 1, r, x, y);
        return res;
    }
}PT;

多源最短路(Johnson算法)

struct Johnson
{
	int n, m, d[N], dis[N], vis[N], Dis[N][N];
	priority_queue <pair<int, int> > q;
	bool Bellman_Ford()
	{
	    for (int i = 1; i <= n; i++) g[0].push_back(MP(i, 0)), d[i] = INF;
	    int flag = 0;
	    for (int i = 1; i <= n; i++)
	    {
	        int Flag = 0;
	        for (int j = 0; j <= n; j++)
	            for (int k = 0; k < g[j].size(); k++)
	            {
	                int v = g[j][k].F, w = g[j][k].S;
	                if (w + d[j] < d[v])
	                    Flag = 1, d[v] = d[j] + w;
	            }
	        if (!Flag)
	        {
	            flag = 1;
	            break;
	        }
	    }
	    return flag;
	}
	
	void Dijkstra(int S)
	{
	    for (int i = 1; i <= n; i++) dis[i] = INF, vis[i] = 0;
	    dis[S] = 0, q.push(MP(0, S));
	    while (!q.empty())
	    {
	        int x = q.top().S;
	        q.pop();
	        if (vis[x]) continue;
	        vis[x] = 1;
	        for (int i = 0; i < g[x].size(); i++)
	        {
	            int v = g[x][i].F, w = g[x][i].S + d[x] - d[v];
	            if (dis[v] > dis[x] + w) dis[v] = dis[x] + w, q.push(MP(-dis[v], v));
	        }
	    }
	    for (int i = 1; i <= n; i++)
	    	Dis[S][i] = dis[i];
	}
	
	void work()
	{
		if (!Bellman_Ford()) puts("exist minus circle"); 
		else for (int i = 1; i <= n; i++) Dijkstra(i);
	}
}J;

线段树

  • 区间加+区间乘+区间求和
struct Segment_Tree
{
    LL tag_a[N * 4], tag_m[N * 4], sum[N * 4], a[N], m;

    void init(int n)
    {
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
    }

    int lc(int k) { return k << 1; }
    int rc(int k) { return k << 1 | 1; }

    void push_up(int k)
    {
        sum[k] = (sum[lc(k)] + sum[rc(k)]) % m;
    }

    void push_down(int k, int l, int r)
    {
        int mid = l + r >> 1;
        sum[lc(k)] = (sum[lc(k)] * tag_m[k] % m + tag_a[k] * (mid - l + 1) % m) % m;
        tag_m[lc(k)] = tag_m[lc(k)] * tag_m[k] % m;
        tag_a[lc(k)] = (tag_a[lc(k)] * tag_m[k] % m + tag_a[k]) % m;

        sum[rc(k)] = (sum[rc(k)] * tag_m[k] % m + tag_a[k] * (r - mid) % m) % m;
        tag_m[rc(k)] = tag_m[rc(k)] * tag_m[k] % m;
        tag_a[rc(k)] = (tag_a[rc(k)] * tag_m[k] % m + tag_a[k]) % m;

        tag_a[k] = 0, tag_m[k] = 1;
    }

    void build(int k, int l, int r)
    {
        tag_m[k] = 1;
        if (l == r) { sum[k] = a[l] % m; return; }
        int mid = l + r >> 1;
        build(lc(k), l, mid);
        build(rc(k), mid + 1, r);
        push_up(k);
    }

    void modify_a(int k, int l, int r, int x, int y, LL v)
    {
        if (x <= l && r <= y)
        {
            sum[k] = (sum[k] + (r - l + 1) * v) % m;
            tag_a[k] = (tag_a[k] + v) % m;
            return;
        }
        push_down(k, l, r);
        int mid = l + r >> 1;
        if (x <= mid) modify_a(lc(k), l, mid, x, y, v);
        if (y >= mid + 1) modify_a(rc(k), mid + 1, r, x, y, v);
        push_up(k);
    }

    void modify_m(int k, int l, int r, int x, int y, LL v)
    {
        if (x <= l && r <= y)
        {
            sum[k] = sum[k] * v % m;
            tag_m[k] = (tag_m[k] * v) % m;
            tag_a[k] = (tag_a[k] * v) % m;
            return;
        }
        push_down(k, l, r);
        int mid = l + r >> 1;
        if (x <= mid) modify_m(lc(k), l, mid, x, y, v);
        if (y >= mid + 1) modify_m(rc(k), mid + 1, r, x, y, v);
        push_up(k);
    }

    LL query(int k, int l, int r, int x, int y)
    {
        if (x <= l && r <= y)
            return sum[k];
        push_down(k, l, r);
        int mid = l + r >> 1;
        LL res = 0;
        if (x <= mid) res += query(lc(k), l, mid, x, y);
        if (y >= mid + 1) res += query(rc(k), mid + 1, r, x, y);
        return res % m;
    }
}ST;
  • 区间加+区间求和+区间求最值
struct Segment_Tree
{
    LL tag_a[N * 4], sum[N * 4], a[N], Max[N * 4], Min[N * 4];

    void init(int n)
    {
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
    }

    int lc(int k) { return k << 1; }
    int rc(int k) { return k << 1 | 1; }

    void push_up(int k)
    {
        sum[k] = sum[lc(k)] + sum[rc(k)];
        Max[k] = max(Max[lc(k)], Max[rc(k)]);
        Min[k] = min(Min[lc(k)], Min[rc(k)]);
    }

    void push_down(int k, int l, int r)
    {
        int mid = l + r >> 1;
        sum[lc(k)] = sum[lc(k)] + tag_a[k] * (mid - l + 1);
        Max[lc(k)] = Max[lc(k)] + tag_a[k];
        Min[lc(k)] = Min[lc(k)] + tag_a[k];
        tag_a[lc(k)] = tag_a[lc(k)] + tag_a[k];

        sum[rc(k)] = sum[rc(k)] + tag_a[k] * (r - mid);
        Max[rc(k)] = Max[rc(k)] + tag_a[k];
        Min[rc(k)] = Min[rc(k)] + tag_a[k];
        tag_a[rc(k)] = tag_a[rc(k)] + tag_a[k];

        tag_a[k] = 0;
    }

    void build(int k, int l, int r)
    {
        if (l == r) { Min[k] = Max[k] = sum[k] = a[l]; return; }
        int mid = l + r >> 1;
        build(lc(k), l, mid);
        build(rc(k), mid + 1, r);
        push_up(k);
    }

    void modify_a(int k, int l, int r, int x, int y, LL v)
    {
        if (x <= l && r <= y)
        {
            sum[k] = sum[k] + (r - l + 1) * v;
            tag_a[k] = tag_a[k] + v;
            Max[k] = Max[k] + v;
            Min[k] = Min[k] + v;
            return;
        }
        push_down(k, l, r);
        int mid = l + r >> 1;
        if (x <= mid) modify_a(lc(k), l, mid, x, y, v);
        if (y >= mid + 1) modify_a(rc(k), mid + 1, r, x, y, v);
        push_up(k);
    }

    LL query_sum(int k, int l, int r, int x, int y)
    {
        if (x <= l && r <= y)
            return sum[k];
        push_down(k, l, r);
        int mid = l + r >> 1;
        LL res = 0;
        if (x <= mid) res += query_sum(lc(k), l, mid, x, y);
        if (y >= mid + 1) res += query_sum(rc(k), mid + 1, r, x, y);
        return res;
    }
    
    LL query_Max(int k, int l, int r, int x, int y)
    {
        if (x <= l && r <= y)
            return Max[k];
        push_down(k, l, r);
        int mid = l + r >> 1;
        LL res = 0;
        if (x <= mid) res = max(res, query_Max(lc(k), l, mid, x, y));
        if (y >= mid + 1) res = max(res, query_Max(rc(k), mid + 1, r, x, y));
        return res;
    }
    
    LL query_Min(int k, int l, int r, int x, int y)
    {
        if (x <= l && r <= y)
            return Min[k];
        push_down(k, l, r);
        int mid = l + r >> 1;
        LL res = INF;
        if (x <= mid) res = min(res, query_Max(lc(k), l, mid, x, y));
        if (y >= mid + 1) res = min(res, query_Max(rc(k), mid + 1, r, x, y));
        return res;
    }
}ST;

树状数组

struct Binary_Index_Tree
{
    LL c[N];
    int n;

    int lowbit(int x)
    {
        return x & (-x);
    }

    void add(int x, int v)
    {
        for (int i = x; i <= n; i += lowbit(i)) c[i] += v;
    }

    LL query_sum(int x)
    {
        LL res = 0;
        while (x) res += c[x], x -= lowbit(x);
        return res;
    }
}BIT;

树链剖分

struct Segment_Tree
{
    LL tag[N * 4], sum[N * 4], a[N];

    int lc(int k) { return k << 1; }
    int rc(int k) { return k << 1 | 1; }

    void push_up(int k)
    {
        sum[k] = (sum[lc(k)] + sum[rc(k)]) % p;
    }

    void push_down(int k, int l, int r)
    {
        int mid = l + r >> 1;
        sum[lc(k)] = (sum[lc(k)] + tag[k] * (mid - l + 1) % p) % p;
        tag[lc(k)] = (tag[lc(k)] + tag[k]) % p;

        sum[rc(k)] = (sum[rc(k)] + tag[k] * (r - mid) % p) % p;
        tag[rc(k)] = (tag[rc(k)] + tag[k]) % p;
        tag[k] = 0;
    }

    void build(int k, int l, int r)
    {
        if (l == r) { sum[k] = a[l] % p; return; }
        int mid = l + r >> 1;
        build(lc(k), l, mid);
        build(rc(k), mid + 1, r);
        push_up(k);
    }

    void modify(int k, int l, int r, int x, int y, LL v)
    {
        if (x <= l && r <= y)
        {
            sum[k] = (sum[k] + v * (r - l + 1) % p) % p;
            tag[k] = (tag[k] + v) % p;
            return;
        }
        push_down(k, l, r);
        int mid = l + r >> 1;
        if (x <= mid) modify(lc(k), l, mid, x, y, v);
        if (y >= mid + 1) modify(rc(k), mid + 1, r, x, y, v);
        push_up(k);
    }

    LL query(int k, int l, int r, int x, int y)
    {
        if (x <= l && r <= y)
            return sum[k];
        push_down(k, l, r);
        int mid = l + r >> 1;
        LL res = 0;
        if (x <= mid) res += query(lc(k), l, mid, x, y);
        if (y >= mid + 1) res += query(rc(k), mid + 1, r, x, y);
        return res % p;
    }
}ST;
struct Heavy_Light_Path_Divide
{
    int son[N], siz[N], top[N], dfn[N], idfn[N], dep[N], f[N], Index, a[N];

    void dfs_1(int x, int fa)
    {
        siz[x] = 1;
        for (int i = 0; i < g[x].size(); i++)
        {
            int v = g[x][i];
            if (v == fa) continue;
            dep[v] = dep[x] + 1, f[v] = x;
            dfs_1(v, x);
            siz[x] += siz[v];
            if (siz[son[x]] < siz[v])
                son[x] = v;
        }
    }

    void dfs_2(int x, int fa, int t)
    {
        dfn[x] = ++Index, idfn[Index] = x, top[x] = t;
        if (son[x])
            dfs_2(son[x], x, t);
        for (int i = 0; i < g[x].size(); i++)
        {
            int v = g[x][i];
            if (v == fa || v == son[x])
                continue;
            dfs_2(v, x, v);
        }
    }

    void modify_path(int x, int y, int v)
    {
        int tx = top[x], ty = top[y];
        while (tx != ty)
        {
            if (dep[tx] > dep[ty])
            {
                ST.modify(1, 1, n, dfn[tx], dfn[x], v);
                x = f[tx], tx = top[x];
            }
            else
            {
                ST.modify(1, 1, n, dfn[ty], dfn[y], v);
                y = f[ty], ty = top[y];
            }
        }
        if (dfn[x] < dfn[y])
            ST.modify(1, 1, n, dfn[x], dfn[y], v);
        else
            ST.modify(1, 1, n, dfn[y], dfn[x], v);
    }

    void modify_sub(int x, LL v)
    {
        ST.modify(1, 1, n, dfn[x], dfn[x] + siz[x] - 1, v);
    }

    LL query_sub(int x)
    {
        return ST.query(1, 1, n, dfn[x], dfn[x] + siz[x] - 1);
    }

    LL query_path(int x, int y)
    {
        LL res = 0;
        int tx = top[x], ty = top[y];
        while (tx != ty)
        {
            if (dep[tx] > dep[ty])
            {
                res = (res + ST.query(1, 1, n, dfn[tx], dfn[x])) % p;
                x = f[tx], tx = top[x];
            }
            else
            {
                res = (res + ST.query(1, 1, n, dfn[ty], dfn[y])) % p;
                y = f[ty], ty = top[y];
            }
        }
        if (dfn[x] < dfn[y])
            res = (res + ST.query(1, 1, n, dfn[x], dfn[y])) % p;
        else
            res = (res + ST.query(1, 1, n, dfn[y], dfn[x])) % p;
        return res;
    }

    void work()
    {
        dfs_1(1, -1);
        dfs_2(1, -1, 1);
        for (int i = 1; i <= n; i++) ST.a[i] = a[idfn[i]];
        ST.build(1, 1, n);
    }
}PD;

Tarjan系列算法

强连通分量(缩点)

struct SCC
{
    int Index, dfn[N], low[N], cnt, S[N], top, Iscc[N], ins[N];
    vector<int> scc[N];

    void Tarjan(int x)
    {
        low[x] = dfn[x] = ++Index;
        ins[x] = 1, S[++top] = x;
        for (int i = 0; i < g[x].size(); i++)
        {
            int v = g[x][i];
            if (!dfn[v])
                Tarjan(v), low[x] = min(low[x], low[v]);
            else if (ins[v])
                low[x] = min(low[x], dfn[v]);
        }
        if (dfn[x] == low[x])
        {
            cnt++; int y;
            do
            {
               y = S[top--], ins[y] = 0;
               scc[cnt].push_back(y), Iscc[y] = cnt, A[cnt] += a[y];
            } while (x != y);
        }
    }

    void work()
    {
        for (int i = 1; i <= n; i++)
            if (!dfn[i]) Tarjan(i);
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < g[i].size(); j++)
            {
                int v = g[i][j];
                if (Iscc[i] != Iscc[v])
                    ng[Iscc[i]].push_back(Iscc[v]);
            }
    }
}SC;

欧拉路

记得跑之前把以每个点为起始点的边按终点排序

void Euler_road(int from)
{
    S[++top] = from;
    while (top)
    {
        int x = S[top];
        while (Now[x] < (int)g[x].size() && vis[x][g[x][Now[x]]] == 1)
            Now[x]++;
        if (Now[x] < (int)g[x].size())
        {
            int v = g[x][Now[x]];
            S[++top] = v, vis[x][v] = vis[v][x] = 1, Now[x]++;
        }
        else
            ans[++ans[0]] = S[top--];
    }
}
posted @ 2024-02-04 16:14  With_penguin  阅读(17)  评论(1编辑  收藏  举报