模板

数据结构

线段树2

void build(int p, int l, int r) {
	l(p) = l, r(p) = r;
	if(l == r) return ;
	int mid = l+r >> 1;
	build(ls(p) = p<<1, l, mid), build(rs(p) = p<<1|1, mid+1, r);
}
void pushdown(int p) {
	sum(ls(p)) = (sum(ls(p)) * mul(p) + add(p) * (r(ls(p)) - l(ls(p))+1)) % mo;
	sum(rs(p)) = (sum(rs(p)) * mul(p) + add(p) * (r(rs(p)) - l(rs(p))+1)) % mo;
	sum(ls(p)) %= mo, sum(rs(p)) %= mo;
	add(ls(p)) = add(ls(p)) * mul(p) + add(p), add(rs(p)) = add(rs(p)) * mul(p) + add(p);
	add(ls(p)) %= mo, add(rs(p)) %= mo;
	mul(ls(p)) = mul(ls(p)) * mul(p) % mo, mul(rs(p)) = mul(rs(p)) * mul(p) % mo;
	add(p) = 0, mul(p) = 1;
}
void changeadd(int p, int l, int r, ll s) {
	if(l(p) >= l && r(p) <= r) {
		sum(p) += s * (r(p) - l(p)+1);
		add(p) += s;
		sum(p) %= mo, add(p) %= mo;
		return ;
	}
	pushdown(p);
	int mid = l(p)+r(p) >> 1;
	if(l <= mid) changeadd(ls(p), l, r, s);
	if(r > mid) changeadd(rs(p), l, r, s);
	sum(p) = (sum(ls(p)) + sum(rs(p))) % mo;
}
void changemul(int p, int l, int r, ll s) {
	if(l(p) >= l && r(p) <= r) {
		sum(p) = sum(p) * s % mo;
		add(p) = add(p) * s % mo;
		mul(p) = mul(p) * s % mo;
		return ;
	}
	pushdown(p);
	int mid = l(p)+r(p) >> 1;
	if(l <= mid) changemul(ls(p), l, r, s);
	if(r > mid) changemul(rs(p), l, r, s);
	sum(p) = (sum(ls(p)) + sum(rs(p))) % mo;
}
ll ask(int p, int l, int r) {
	if(l(p) >= l && r(p) <= r) return sum(p);
	pushdown(p);
	int mid = l(p)+r(p) >> 1;
	ll res = 0;
	if(l <= mid) res += ask(ls(p), l, r);
	if(r > mid) res += ask(rs(p), l, r);
	return res % mo;
}

主席树

int n, m, tot, cnt, a[N], num[N], rt[N];
struct tree {
    int ls, rs, sum;
    #define ls(p) t[p].ls
    #define rs(p) t[p].rs
    #define sum(p) t[p].sum
} t[N];

int get(int x) {
    return lower_bound(num+1, num+cnt+1, x) - num;
}
// int build(int l, int r) { // 初始形态
//     int p = ++tot;
//     if(l == r) return p;
//     int mid = l+r>>1;
//     ls(p) = build(l, mid);
//     rs(p) = build(mid+1, r);
//     return p;
// }
void insert(int root, int &p, int k, int l, int r) { // 返回根
    p = ++tot;
    ls(p) = ls(root), rs(p) = rs(root), sum(p) = sum(root)+1;
    if(l == r) return ;
    int mid = l+r>>1;
    if(k <= mid) insert(ls(root), ls(p), k, l, mid);
    else insert(rs(root), rs(p), k, mid+1, r);
}
int ask(int x, int y, int k, int l, int r) {
    if(l == r) return l;
    int mid = l+r>>1, s = sum(ls(y)) - sum(ls(x));
    if(s < k) return ask(rs(x), rs(y), k - s, mid+1, r);
    return ask(ls(x), ls(y), k, l, mid);
}

扫描线 (线段/面积并)

namespace sgt {
	#define ls(p) p<<1
	#define rs(p) p<<1|1
	int len[N<<2], tag[N<<2];
	void pushup(int p, int a, int b) {
		len[p] = a == b ? 0 : len[ls(p)] + len[rs(p)];
	}
	void modify(int p, int l, int r, int x, int y, int k) {
		if(l >= x && r <= y) {
			tag[p] += k;
			if(tag[p]) len[p] = ::x[r+1] - ::x[l];
			else pushup(p, l, r);
			return ;
		}
		int mid = l+r>>1;
		if(x <= mid) modify(ls(p), l, mid, x, y, k);
		if(y > mid) modify(rs(p), mid+1, r, x, y, k);
		if(!tag[p]) pushup(p, l, r);
	}
}
using sgt::modify;
using sgt::len;

线段树合并

struct tree {
    // 权值线段树: 维护值域(颜色)[l,r]区间的信息(此处为个数)
    int rt, ls, rs, res, sum;
    #define rt(p) t[p].rt
    #define res(p) t[p].res
    #define sum(p) t[p].sum
    #define ls(p) t[p].ls
    #define rs(p) t[p].rs
} t[N+3<<7];
void update(int p) {
    if(sum(ls(p)) >= sum(rs(p))) sum(p) = sum(ls(p)), res(p) = res(ls(p));
    else sum(p) = sum(rs(p)), res(p) = res(rs(p));
}
int merge(int a, int b, int l, int r) {
    if(!a) return b;
    if(!b) return a;
    if(l == r) {
        sum(a) += sum(b);
        return a;
    }
    int mid = l+r>>1;
    ls(a) = merge(ls(a), ls(b), l, mid);
    rs(a) = merge(rs(a), rs(b), mid+1, r);
    update(a);
    return a;
}
int tot;
int add(int id, int l, int r, int col, int val) {
    if(!id) id = ++tot;
    if(l == r) {
        res(id) = col;
        sum(id) += val;
        return id;
    }
    int mid = l+r>>1;
    if(col <= mid) ls(id) = add(ls(id), l, mid, col, val);
    else rs(id) = add(rs(id), mid+1, r, col, val);
    update(id);
    return id;
}

李超线段树

void update(int p, int l, int r, int k) {
	if(l > tr[p].r || r < tr[p].l) return ;
	if(l <= tr[p].l && r >= tr[p].r) {
		if(check(k, tr[p].dat, tr[p].l) && check(k, tr[p].dat, tr[p].r)) return ; // worse
		if(check(tr[p].dat, k, tr[p].l) && check(tr[p].dat, k, tr[p].r)) {
			tr[p].dat = k;
			return ; // better
		}
		int mid = tr[p].l+tr[p].r >> 1;
		if(check(tr[p].dat, k, mid)) swap(tr[p].dat, k);
		if(check(tr[p].dat, k, tr[p].l)) update(tr[p].ls, tr[p].l, tr[p].r, k);
		else update(tr[p].rs, tr[p].l, tr[p].r, k);
	}
	else update(tr[p].ls, l, r, k), update(tr[p].rs, l, r, k);
}
int query(int p, int k) {
	if(k < tr[p].l || k > tr[p].r) return 0;
	if(tr[p].l == tr[p].r && tr[p].l == k) return tr[p].dat;
	int mid = tr[p].l+tr[p].r >> 1, res;
	if(k <= mid) res = query(tr[p].ls, k);
	else res = query(tr[p].rs, k);
	if(check(res, tr[p].dat, k)) res = tr[p].dat;
	return res;
}

Splay

int n, m, fa[N], son[N][2], val[N], cnt[N], sz[N];
//        父亲   儿子        值      个数    子树大小
int rt, tot;

struct Splay {
    void clear(int x) {fa[x]=son[x][0]=son[x][1]=val[x]=cnt[x]=sz[x] = 0;}
    void update(int x) {sz[x] = sz[son[x][0]] + sz[son[x][1]] + cnt[x];}
    bool get(int x) {return x == son[fa[x]][1];} // 左右儿子
    void rotate(int x) {
        int y = fa[x], z = fa[y], k = get(x);
        son[y][k] = son[x][k^1];
        if(son[x][k^1]) fa[son[x][k^1]] = y;
        son[x][k^1] = y;
        fa[y] = x, fa[x] = z;
        if(z) son[z][y == son[z][1]] = x;
        update(y), update(x); // 注意顺序
    }
    void splay(int x) {
        for(int f; f = fa[x]; rotate(x)) {
            if(fa[f]) rotate(get(x) == get(f) ? f:x);
        }
        rt = x;
    }
    int rnk(int k) {
      	ins(x);
        int res = 0, cur = rt;
        while(1) {
            if(k < val[cur]) cur = son[cur][0];
            else {
                res += sz[son[cur][0]];
                if(val[cur] == k) {
                    splay(cur);
                    return res+1;
                }
                res += cnt[cur], cur = son[cur][1];
            }
        }
      	del(x);
    }
    int kth(int k) {
        int cur = rt;
        while(1) {
            if(son[cur][0] && k <= sz[son[cur][0]]) cur = son[cur][0];
            else {
                k -= cnt[cur] + sz[son[cur][0]];
                if(k <= 0) {
                    splay(cur);
                    return val[cur];
                }
                cur = son[cur][1];
            }
        }
    }
    void ins(int k) {
        if(!rt) {
            val[rt = ++tot] = k, cnt[tot]++;
            update(rt);
            return ;
        }
        int cur = rt, f=0;
        while(cur) {
            if(val[cur] == k) {
                cnt[cur]++;
                update(cur), update(f);
                splay(cur);
                return ;
            }
            f = cur, cur = son[cur][val[cur] < k];
        }
        val[++tot] = k, cnt[tot]++;
        fa[tot] = f, son[f][val[f] < k] = tot;
        update(tot), update(f);
        splay(tot);
    }
    int pre() {
        int cur = son[rt][0];
        if(!cur) return cur;
        while(son[cur][1]) cur = son[cur][1];
        splay(cur);
        return cur;
    }
    int suf() {
        int cur = son[rt][1];
        if(!cur) return cur;
        while(son[cur][0]) cur = son[cur][0];
        splay(cur);
        return cur;
    }
    void del(int k) {
        rnk(k); // 转到根节点
        if(cnt[rt]-- > 1) {
            update(rt);
            return ;
        }
        if(!son[rt][0] && !son[rt][1]) {
            clear(rt);
            rt = 0;
            return ;
        }
        int cur = rt;
        if(!son[rt][0]) {
            rt = son[rt][1], fa[rt] = 0;
            clear(cur);
            return ;
        }
        if(!son[rt][1]) {
            rt = son[rt][0], fa[rt] = 0;
            clear(cur);
            return ;
        }
        int x = pre();
        fa[son[cur][1]] = x, son[x][1] = son[cur][1];
        clear(cur), update(rt);
    }
} tree;

2D-BIT

struct BIT {
	#define lb(i) i&-i
	int a[N][N], ai[N][N], aj[N][N], aij[N][N];
	void add(int i, int j, int x) {
		for(int ii=i; ii <= n; ii += lb(ii)) {
			for(int jj=j; jj <= m; jj += lb(jj)) {
				a[ii][jj] += x;
				ai[ii][jj] += x * i;
				aj[ii][jj] += x * j;
				aij[ii][jj] += x * i*j;
			}
		}
	}
	int ask(int i, int j) {
		int s=0;
		for(int ii=i; ii; ii -= lb(ii)) {
			for(int jj=j; jj; jj -= lb(jj)) {
				s += aij[ii][jj];
				s -= aj[ii][jj] * (i+1);
				s -= ai[ii][jj] * (j+1);
				s += a[ii][jj] * (i+1)*(j+1);
			}
		}
		return s;
	}
	#define y1 yone
	void add(int x1, int y1, int x2, int y2, int v) {
		add(x1, y1, v);
		add(x1, y2+1, -v);
		add(x2+1, y1, -v);
		add(x2+1, y2+1, v);
	}
	int ask(int x1, int y1, int x2, int y2) {
		int s=0;
		s += ask(x1-1, y1-1);
		s -= ask(x1-1, y2);
		s -= ask(x2, y1-1);
		s += ask(x2, y2);
		return s;
	}
}

回滚莫队

    rep(j, 1, bn) {
        int br = min(j*len, n), l = br+1, r = l-1, cnt=0, res=0;
        for(; b[q[i].l] == j; ++i) {
            if(b[q[i].r] == j) {ans[q[i].i] = calc(q[i].l, q[i].r); continue;} // bf
            while(r < q[i].r) {
                ++r;
                lst[a[r]] = r;
                if(!fst[a[r]]) fst[a[r]]=r, del[++cnt] = a[r];
                res = max(res, r - fst[a[r]]);
            }
            int tmp = res;
            while(l > q[i].l) {
                --l;
                if(lst[a[l]]) res = max(res, lst[a[l]] - l);
                else lst[a[l]] = l;
            }
            ans[q[i].i] = res;
            while(l <= br) {
                if(lst[a[l]] == l) lst[a[l]] = 0;
                ++l;
            }
            res = tmp;
        }
        rep(i, 1, cnt) fst[del[i]] = lst[del[i]] = 0;
    }

01 Trie(Xor Mst)

int n, rt;
struct trie {
    int a[N], ch[2][N<<5], cnt, l[N<<5], r[N<<5];
    void ins(int &k, int id, int dep) {
        if(!k) k = ++cnt;
        if(!~dep) return ;
        if(!l[k]) l[k] = id;
        r[k] = id;
        ins(ch[a[id]>>dep&1][k], id, dep-1);
    }
    ll ask(int k, int x, int dep) {
        if(!~dep) return 0;
        int b = x>>dep&1;
        if(ch[b][k]) return ask(ch[b][k], x, dep-1);
        return ask(ch[b^1][k], x, dep-1) + (1<<dep);
    }
    ll dfs(int k, int dep) {
        if(!~dep) return 0;
        if(ch[0][k] && ch[1][k]) {
            ll res = INF;
            rep(i, l[ch[0][k]], r[ch[0][k]]) res = min(res, ask(ch[1][k], a[i], dep-1) + (1<<dep));
            return res + dfs(ch[0][k], dep-1) + dfs(ch[1][k], dep-1);
        }
        if(ch[0][k]) return dfs(ch[0][k], dep-1);
        if(ch[1][k]) return dfs(ch[1][k], dep-1);
        return 0;
    }
    void solve() {
        in(a, n);
        sort(a+1, a+n+1);
        rep(i, 1, n) ins(rt, i, 30);
        wr(dfs(rt, 30));
    }
} tr;

可持久化并查集

字符串

KMP

void kmp() {
	int j=0;
	rep(i, 2, n) {
		while(j && s[i] != s[j+1]) j = nxt[j];
		if(s[i] == s[j+1]) ++j;
		nxt[i] = j;
	}
}

manacher

void manacher() {
	scanf("%s", str);
	n = strlen(str);
	rep(i, 0, n) {
		s[i<<1|1] = '#';
		s[i+1<<1] = str[i];
	}
	n = n<<1|1;
	s[0] = '~';
//	rep(i, 0, n) pc(s[i]);
	int mxr=0, p=0;
	rep(i, 1, n) {
		if(i < mxr) f[i] = min(f[2*p-i], mxr-i);
		else f[i] = 1;
		while(s[i+f[i]] == s[i-f[i]]) f[i]++;
		if(i+f[i] > mxr) mxr = i+f[i], p=i;
		ans = max(ans, f[i]-1);
	}
}

AC Automaton

struct ACAM {
    int nxt[30][N], fail[N], ed[N], cnt[N], tot;
    void clear() {
        mem(nxt, 0);
        mem(fail, 0);
        mem(ed, 0);
        mem(cnt, 0);
        tot = 0;
    }
    void insert(char *s, int id) {
        int n = strlen(s), p=0;
        rep(i, 0, n-1) {
            int k = s[i]-'a';
            if(!nxt[k][p]) nxt[k][p] = ++tot;
            p = nxt[k][p];
        }
        ed[p] = id;
    }
    void getfail() {
        queue <int> q;
        rep(i, 0, 25) if(nxt[i][0]) q.push(nxt[i][0]);
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            rep(i, 0, 25) {
                if(!nxt[i][u]) nxt[i][u] = nxt[i][fail[u]];
                else q.push(nxt[i][u]), fail[nxt[i][u]] = nxt[i][fail[u]];
            }
        }
    }
    void ask(char *s) {
        int n = strlen(s), p=0, res=0;
        rep(i, 0, n-1) {
            int k = s[i]-'a';
            p = nxt[k][p];
            for(int j=p; j; j=fail[j]) cnt[ed[j]]++;
        }
    }
} acam;

Z Algorithm

void exkmp(string s) {
	n = s.size();
	for(i = 1; i < n; ++i) {
		if(j+z[j] > i) z[i] = min(z[i-j], j+z[j]-i);
		while(s[z[i]] == s[i+z[i]]) ++z[i];
		if(j+z[j] < i+z[i]) j=i;
	}
}

Minshow

int minshow() {
    int i=0, j=1, k=0;
    while(i<n && j<n && k<n) {
        if(a[(i+k)%n] == a[(j+k)%n]) k++;
        else {
            if(a[(i+k)%n] > a[(j+k)%n]) i += k+1;
            else j += k+1;
            if(i == j) j++;
            k = 0;
        }
    }
    return min(i, j);
}

SA

// 数组记得开两倍
void suffix_sort() {
	int m = 128;
	rep(i, 1, n) cnt[rk[i] = s[i]]++;
	rep(i, 1, m) cnt[i] += cnt[i-1];
	per(i, n, 1) sa[cnt[rk[i]]--] = i;
	for(int k=1, p=0; p != n; k <<= 1, m = p) {
		int tot = 0;
		rep(i, n-k+1, n) id[++tot] = i;
		rep(i, 1, n) if(sa[i] > k) id[++tot] = sa[i]-k;
		mem(cnt, 0);
		rep(i, 1, n) cnt[rk[i]]++;
		rep(i, 1, m) cnt[i] += cnt[i-1];
		per(i, n, 1) sa[cnt[rk[id[i]]]--] = id[i];
		p = 0;
		memcpy(lstrk, rk, sizeof(lstrk));
		rep(i, 1, n) {
			if(lstrk[sa[i]] == lstrk[sa[i-1]] && lstrk[sa[i]+k] == lstrk[sa[i-1]+k]) rk[sa[i]] = p;
			else rk[sa[i]] = ++p;
		}
	}
}

图论

Tarjan

割点 and 点双

桥 and 边双

缩点:

边双 \(\to\)

强连通 \(\to\) DAG

点双 \(\to\) 圆方树

边双

void tarjan(int u, int cur) {
	dfn[u] = low[u] = ++cnt;
	for(int i = h[u]; i; i = e[i].n) {
		int v = e[i].v;
		if(!dfn[v]) {
			tarjan(v, i);
			if(dfn[u] < low[v]) bridge[i] = bridge[i^1] = 1;
			low[u] = min(low[u], low[v]);
		}
		else if(i != (cur ^ 1)) low[u] = min(low[u], dfn[v]);
	}
}
void dfs(int u, int id) {
	edcc[u] = id;
	v[id].pb(u);
	for(int i = h[u]; i; i = e[i].n) {
		int v = e[i].v;
		if(edcc[v] || bridge[i]) continue;
		dfs(v, id);
	}
}

强连通

void tarjan(int u) {
    dfn[u]=low[u] = ++t;
    sta[++top] = u, vis[u] = 1;
    for(int i = h[u]; i; i = e[i].n) {
        int v = e[i].v;
        if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]) {
        sum++;
        do {
            scc[u] = sum;
            vis[u = sta[top--]] = 0;
            S[sum].push_back(u);
        } while(low[u] != dfn[u]);
    }
}

点双

void tarjan(int u, int fa) {
	dfn[u]=low[u] = ++cnt;
	st[++top] = u;
	int son=0;
	for(int i=h[u]; i; i=e[i].n) {
		int v=e[i].v;
		if(v == fa) continue;
		if(!dfn[v]) {
			son++;
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if(low[v] >= dfn[u]) {
				++vdcc;
				while(st[top+1] != v) ans[vdcc].pb(st[top--]);
				ans[vdcc].pb(u);
			}
		}
		else low[u] = min(low[u], dfn[v]);
	}
	if(!fa && !son) ans[++vdcc].pb(u);
}

最大流

int bfs() {
    mem(vis, 0);
    queue <int> q;
    q.push(S);
    vis[S] = 1;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i=h[u]; i; i=e[i].n) {
            int v=e[i].v, w=e[i].w;
            if(!vis[v] && w) vis[v] = vis[u]+1, q.push(v);
        }
    }
    return vis[T];
}
ll dfs(int u, int d) {
    if(u == T) return d;
    ll s=0;
    for(int i=h[u]; i; i=e[i].n) {
        int v=e[i].v, w = min(e[i].w, d);
        if(vis[v] == vis[u]+1 && w) {
            int k = dfs(v, w);
            s += k, d -= k;
            e[i].w -= k, e[i^1].w += k;
        }
    }
    return s ? s : vis[u]=0;
}
ll dinic() {
    ll ans = 0;
    while(bfs()) {
        ans += dfs(S, INF);
    }
    return ans;
}

费用流

void bfs() {
    queue <int> q;
    q.push(S);
    vis[S] = INF, dis[S] = 0;
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        use[u] = 0;
        for(int i=h[u]; i; i=e[i].n) {
            int v=e[i].v, w=e[i].w, c=e[i].c;
            if(dis[u]+c < dis[v] && w) {
                vis[v] = min(vis[u], w);
                pre[v] = i, dis[v] = dis[u]+c;
                if(!use[v]) q.push(v), use[v] = 1;
            }
        }
    }
    for(int i=pre[T]; i; i=pre[e[i].u]) {
        e[i].w -= vis[T];
        e[i^1].w += vis[T];
    }
}
void mcmf() {
    while(1) {
        mem(vis, 0);
        mem(dis, INF);
        mem(pre, 0);
        mem(use, 0);
        bfs();
        if(vis[T]) maxflow += vis[T], mincost += vis[T]*dis[T];
        else return ;
    }
}

二分图最大匹配

int dfs(int u) {
    if(vis[u]) return 0;
    vis[u] = 1;
	for(int i = 0; i < G[u].size(); ++i) {
	    int v = G[u][i];
		if(!p[v] || dfs(p[v])) {
			p[v] = u;
			return 1;
		}
	}
	return 0;
}

图的匹配

点分治

namespace TreeDivide {
	void getrt(int u, int fa) {
		int sz = 0;
		size[u] = 1;
		for(int i=h[u]; i; i=e[i].n) {
			int v = e[i].v;
			if(v == fa || vis[v]) continue;
			getrt(v, u);
			size[u] += size[v];
			sz = max(sz, size[v]);
		}
		sz = max(sz, sum - size[u]);
		if(sz < mnsz) rt=u, mnsz=sz;
	}
	void getdis(int u, int fa) {
		d[++cnt] = dis[u];
		for(int i=h[u]; i; i=e[i].n) {
			int v = e[i].v, w = e[i].w;
			if(v == fa || vis[v]) continue;
			dis[v] = dis[u]+w;
			getdis(v, u);
		}
	}
	void solve(int u) {
//		printf("# %d\n", u);
		vis[u]=fl[0] = 1;
		vector <int> tmp;
		for(int i=h[u]; i; i=e[i].n) {
			int v = e[i].v, w = e[i].w;
			if(vis[v]) continue;
			cnt=0, dis[v] = w;
			getdis(v, u);
			rep(j, 1, cnt) rep(k, 1, m) if(q[k] >= d[j]) ans[k] |= fl[q[k]-d[j]];
			rep(j, 1, cnt) if(d[j] < V) tmp.pb(d[j]), fl[d[j]] = 1;
		}
		for(int x : tmp) fl[x]=0;
		for(int i=h[u]; i; i=e[i].n) {
			int v = e[i].v;
			if(vis[v]) continue;
			mnsz = INF, sum = size[v];
			getrt(v, u);
			solve(rt);
		}
	}
}
using TreeDivide::getrt;
using TreeDivide::solve;

重链剖分 (hld)

int sz[N], dep[N], son[N], fa[N], id[N], cnt, p[N], tp[N];

namespace hld {
	void dfs1(int u, int f) {
		dep[u] = dep[f]+1, sz[u]=1, fa[u]=f;
		for(int i=h[u]; i; i=e[i].n) {
			int v = e[i].v;
			if(v == f) continue;
			dfs1(v, u);
			if(sz[v] > sz[son[u]]) son[u]=v;
			sz[u] += sz[v];
		}
	}
	void dfs2(int u, int top) {
		id[u] = ++cnt, p[cnt] = u, tp[u] = top;
		if(!son[u]) return ;
		dfs2(son[u], top);
		for(int i=h[u]; i; i=e[i].n) {
			int v = e[i].v;
			if(v == fa[u] || v == son[u]) continue;
			dfs2(v, v);
		}
	}
	struct sgt {
		ll t[N<<2], tag[N<<2];
		#define ls(p) p<<1
		#define rs(p) p<<1|1
		void pushup(int p) {
			t[p] = (t[ls(p)]+t[rs(p)])%mo;
		}
		void pushdown(int p, int len) {
			if(!tag[p]) return ;
			(t[ls(p)] += tag[p]*(len+1>>1)%mo) %= mo, (t[rs(p)] += tag[p]*(len>>1)%mo) %= mo;
			(tag[ls(p)] += tag[p]) %= mo, (tag[rs(p)] += tag[p]) %= mo;
			tag[p]=0;
		}
		void add(int p, int l, int r, int x, int y, int k) {
			if(l >= x && r <= y) {
				t[p] += k * (r-l+1)%mo, tag[p] += k;
				return ;
			}
			pushdown(p, r-l+1);
			int mid = l+r>>1;
			if(x <= mid) add(ls(p), l, mid, x, y, k);
			if(y > mid) add(rs(p), mid+1, r, x, y, k);
			pushup(p);
		}
		ll ask(int p, int l, int r, int x, int y) {
			if(l >= x && r <= y) return t[p];
			pushdown(p, r-l+1);
			int mid = l+r>>1; ll s=0;
			if(x <= mid) s += ask(ls(p), l, mid, x, y);
			if(y > mid) s += ask(rs(p), mid+1, r, x, y);
			return s%mo;
		}
	} tr;
	void add(int x, int y, int v) {
		while(tp[x] != tp[y]) {
			if(dep[tp[x]] < dep[tp[y]]) swap(x, y);
			tr.add(1, 1, n, id[tp[x]], id[x], v);
			x = fa[tp[x]];
		}
		if(dep[x] > dep[y]) swap(x, y);
		tr.add(1, 1, n, id[x], id[y], v);
	}
	ll ask(int x, int y) {
		ll s=0;
		while(tp[x] != tp[y]) {
			if(dep[tp[x]] < dep[tp[y]]) swap(x, y);
			s += tr.ask(1, 1, n, id[tp[x]], id[x]);
			x = fa[tp[x]];
		}
		if(dep[x] > dep[y]) swap(x, y);
		(s += tr.ask(1, 1, n, id[x], id[y])) %= mo;
		return s;
	}
}
using hld::dfs1;
using hld::dfs2;
using hld::add;
using hld::ask;
using hld::tr;

长链剖分 树上K级祖先

欧拉路

posted @ 2024-11-21 21:45  lowbit  阅读(32)  评论(0)    收藏  举报