代码模板

代码模板大全

数据结构

线段树

标记永久化版本。

区间修改+区间查询

struct Segment_Tree
{
    struct node
    {
        int l, r, sum, lazy;
    }tr[N << 4];

    void push_up(int u)
    {
        tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
    }
    void build(int u, int l, int r)
    {
        tr[u].l = l, tr[u].r = r;
        if(l == r){
            tr[u].sum = a[l];
            return ;
        }
        int mid = (l + r) / 2;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        push_up(u);
    }
    void update(int u, int l, int r, int k)
    {
        if(l <= tr[u].l && tr[u].r <= r){
            tr[u].lazy += k;
            return ;
        }
        tr[u].sum += (min(r, tr[u].r) - max(l, tr[u].l) + 1) * k;
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l <= mid) update(u << 1, l, r, k);
        if(r >  mid) update(u << 1 | 1, l, r, k);
    }
    int query(int u, int l, int r)
    {
        if(l <= tr[u].l && tr[u].r <= r) {
            return tr[u].sum + (tr[u].r - tr[u].l + 1) * tr[u].lazy;
        }
        int res = (min(r, tr[u].r) - max(l, tr[u].l) + 1) * tr[u].lazy;
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l <= mid) res += query(u << 1, l, r);
        if(r >  mid) res += query(u << 1 | 1, l, r);
        return res;
    }
}seg;

区间乘法/区间加法+区间查询

struct node
{
    int l, r, sum, add, mul;
}tree[N << 4];
int a[N], p;

void pushup(int u)
{
    tree[u].sum = (tree[lson].sum + tree[rson].sum) %  p;
}

void build(int u, int l, int r)
{
    if (l == r) tree[u] = {l, r, a[l], 0, 1};
    else
    {
        tree[u] = {l, r, 0, 0, 1};
        int mid = (l + r) >> 1;
        build(lson, l, mid), build(rson, mid + 1, r);
        pushup(u);
    }
}

void cal(node &t, int add, int mul)
{
    t.sum = (t.sum * mul + (t.r - t.l + 1) * add) % p;
    t.add = (t.add * mul + add) % p;
    t.mul = (t.mul * mul) % p;
}

void pushdown(int u)
{
    cal(tree[lson], tree[u].add, tree[u].mul);
    cal(tree[rson], tree[u].add, tree[u].mul);
    tree[u].add = 0;
    tree[u].mul = 1;
}

void update(int u, int l, int r, int add, int mul)
{
    if(l <= tree[u].l && tree[u].r <= r) cal(tree[u], add, mul);
    else {
        pushdown(u);
        int mid = (tree[u].l + tree[u].r) >> 1;
        if(l <= mid) update(lson, l, r, add, mul);
        if(r >  mid) update(rson, l, r, add, mul);
        pushup(u);
    }
}

int query(int u, int l, int r)
{
    if(l <= tree[u].l && tree[u].r <= r) return tree[u].sum;
    
    pushdown(u);
    
    int mid = (tree[u].l + tree[u].r) >> 1;
    int res = 0;
    if(l <= mid) res += query(lson, l, r);
    if(r >  mid) res = (res + query(rson, l, r)) % p;
    
    return res;
}

区间最值

struct node{
    ll mmax,l,r;
    ll tag1,tag2;//修改,加
}t[N<<2];
ll n,q,a[N];

void up(ll k){
    t[k].mmax=max(t[k<<1].mmax,t[k<<1|1].mmax);
}

void rev(ll k,ll x,ll y){
    if(x==1e9+1){
        t[k].tag2+=y;
        t[k].mmax+=y;
    }
    else{
        t[k].tag1=x;
        t[k].tag2=y;
        t[k].mmax=x+y;
    }
}

void pd(ll k){
    rev(k<<1,t[k].tag1,t[k].tag2);
    rev(k<<1|1,t[k].tag1,t[k].tag2);
    t[k].tag1=1e9+1;
    t[k].tag2=0;
}

/*void downtag1(ll k){
    if(t[k].tag1!=1e9+1){
        t[k<<1].mmax=t[k<<1].tag1=t[k].tag1;
        t[k<<1].tag2=0;
        t[k<<1|1].mmax=t[k<<1|1].tag1=t[k].tag1;
        t[k<<1|1].tag2=0;
        t[k].tag1=1e9+1;
    }
}

void downtag2(ll k){
    t[k<<1].tag2+=t[k].tag2;
    t[k<<1].mmax+=t[k].tag2;
    t[k<<1|1].tag2+=t[k].tag2;
    t[k<<1|1].mmax+=t[k].tag2;
    t[k].tag2=0;
}*/

void build(ll k,ll l,ll r){
    t[k].l=l,t[k].r=r,t[k].tag1=1e9+1;
    if(l==r){
        t[k].mmax=a[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    up(k);
}

void change1(ll k,ll l,ll r,ll x){
    if(t[k].l>=l && t[k].r<=r){
        t[k].mmax=x;
        t[k].tag1=x,t[k].tag2=0;
        return ;
    }
    pd(k);
    //downtag1(k),downtag2(k);
    ll mid=(t[k].l+t[k].r)>>1;
    if(l<=mid) change1(k<<1,l,r,x);
    if(r>mid) change1(k<<1|1,l,r,x);
    up(k);
}

void change2(ll k,ll l,ll r,ll x){
    if(t[k].l>=l && t[k].r<=r){
        t[k].mmax+=x;
        t[k].tag2+=x;
        return ;
    }
    pd(k);
    //downtag1(k),downtag2(k);
    ll mid=(t[k].l+t[k].r)>>1;
    if(l<=mid) change2(k<<1,l,r,x);
    if(r>mid) change2(k<<1|1,l,r,x);
    up(k);
}

ll query(ll k,ll l,ll r){
    if(t[k].l>=l && t[k].r<=r) return t[k].mmax;
    pd(k);
    //downtag1(k),downtag2(k);
    ll mid=(t[k].l+t[k].r)>>1;
    ll ans=-1e18;
    if(l<=mid) ans=max(ans,query(k<<1,l,r));
    if(r>mid) ans=max(ans,query(k<<1|1,l,r));
    return ans;
}

可持久化线段树

单点修改

struct node
{
    int l, r;
    int lch, rch;
    int v;
    
};

vector<node> tr;
int rt[N], a[N];

inline int build(int l, int r)
{
    if(l == r) tr.push_back({l, r, -1, -1, a[l]});
    else 
    {
        int mid = (l + r) >> 1;
        int lch = build(l, mid), rch = build(mid + 1, r);
        tr.push_back({l, r, lch, rch, 0});
    }
    return tr.size() - 1;
}

inline int update(int u, int loc, int val)
{
    if(tr[u].l == tr[u].r)
    {
        tr.push_back({tr[u].l, tr[u].r, -1, -1, val});
    }
    else 
    {
        int mid = (tr[u].l + tr[u].r) >> 1;
        int lch = tr[u].lch, rch = tr[u].rch;
        if(loc <= mid) lch = update(tr[u].lch, loc, val);
        if(loc >  mid) rch = update(tr[u].rch, loc, val);
        tr.push_back({tr[u].l, tr[u].r, lch, rch, 0});
    }
    return tr.size() - 1;
}

inline int query(int u, int loc)
{ 
   if(tr[u].l == tr[u].r) return tr[u].v;
   int mid = (tr[u].l + tr[u].r) >> 1;
   if(loc <= mid) return query(tr[u].lch, loc);
   if(loc >  mid) return query(tr[u].rch, loc);
}

int main()
{
    int n = read, m = read;
    for(int i = 1;i <= n;i ++ )
    {
        a[i] = read;
    }
    
    rt[0] = build(1, n);
    
    for(int i = 1;i <= m;i ++ )
    {
        int v = read, op = read, loc = read;
        if(op == 1)
        {
            int val = read;
            rt[i] = update(rt[v], loc, val);
        }
        else 
        {
            cout << query(rt[v], loc) << endl;
            rt[i] = rt[v];
        }
    }
    return 0;
}

查询 k 小值

struct node
{
    int l, r, sum;
}tr[N << 5];

int a[N], b[N], rt[N], cnt;

int update(int u, int l, int r, int x)
{
    int new_ = ++cnt;
    tr[new_].l = tr[u].l, tr[new_].r = tr[u].r, tr[new_].sum = tr[u].sum + 1;

    int mid = (l + r) / 2;
    if(l < r)
    {
        if(x <= mid) tr[new_].l = update(tr[u].l, l, mid, x);
        else tr[new_].r = update(tr[u].r, mid + 1, r, x);
    }
    return new_;
}

int query(int u, int v, int l, int r, int k)
{
    if(l == r) return l;
    int x = tr[tr[v].l].sum - tr[tr[u].l].sum; // 提取 [l, r] 线段树
    int mid = (l + r) >> 1;
    if(k <= x) return query(tr[u].l, tr[v].l, l, mid, k);
    else return query(tr[u].r, tr[v].r, mid + 1, r, k - x);
}

int main()
{
    int n = read, m = read;
 
    for(int i = 1;i <= n;i ++ ) a[i] = read, b[i] = a[i];

    // 离散化 B
    sort(b + 1, b + 1 + n);
    int len = unique(b + 1, b + 1 + n) - b - 1;

    for(int i = 1;i <= n;i ++ ) {
        int x = lower_bound(b + 1, b + 1 + len, a[i]) - b;
        rt[i] = update(rt[i - 1], 1, len, x);
    }

    while(m -- )
    {
        int x = read, y = read, k = read;

        cout << b[query(rt[x - 1], rt[y], 1, len, k)] << endl;
    }
    return 0;
}

平衡树

并查集

int find(int x)
{
	if(f[x] == x) return x;
	return f[x] = find(f[x]);
}
/*
合并:f[find(a)] = find(b);
查询:find(a) == find(b)
*/

分块

区间查询+区间修改

void update(int x,int y,int k)
{
	int l = pos[x],r = pos[y];
	if(l == r){
		for(int i = x;i <= y;i ++ ){
			a[i] +=k;
		}
		sum[l] += k * (y - x + 1);
	}
	else{
		for(int i = l + 1;i < r;i ++ ) add[i] += k;
		for(int i = x;i <= ed[l];i ++ ) a[i] += k;
		sum[l] += k * (ed[l] - x + 1);
		for(int i = st[r];i <= y;i ++ ) a[i] += k;
		sum[r] += k * (y - st[r] + 1);
	}
}

int query(int x,int y)
{
	long long ans = 0;
	int l = pos[x],r = pos[y];
	if(l == r){
		for(int i = x;i <= y;i ++ ){
			ans += a[i];
		}
		ans += add[l] * (y - x + 1);
	}
	else{
		for(int i = l + 1;i < r;i ++ ) ans += sum[i] + (ed[i] - st[i] + 1) * add[i];
		for(int i = x;i <= ed[l];i ++ ) ans += a[i];
		ans += add[l] * (ed[l] - x + 1);
		for(int i = st[r];i <= y;i ++ ) ans += a[i];
		ans += add[r] * (y - st[r] + 1);
	}
	return ans;
}

signed main()
{
	int n, m;
	cin >> n >> m;
	
	for(int i = 1;i <= n;i ++ )
	{
		cin >> a[i];
	}
	int block = sqrt(n);
	int cnt = n / block;
	if(n % block) cnt ++ ;
	for(int i = 1;i <= cnt;i ++ ){
		st[i] = (i - 1) * block + 1;
		ed[i] = i * block;
	}
	ed[cnt] = n;
	for(int i = 1;i <= n;i ++ ) pos[i] = (i - 1) / block + 1;
	for(int i = 1;i <= cnt;i ++ ){
		for(int j = st[i];j <= ed[i];j ++ ){
			sum[i] += a[j];
		}
	}
	while(m -- )
	{
		int op, x, y, k;
		cin >> op ;
		if(op == 1)
		{
			cin>>x>>y>>k;
			update(x, y, k);
		}
		else {
			cin >> x >> y;
			cout <<query(x, y) << endl;
		}
	}
	return 0;
}

区间修改+区间大于小于

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,q;
int a[N],b[N];
int block,tot;
int L[N],R[N];
int x,y,k;
int lazy[N];
int ans;
int belong[N];
void init(){
	block=sqrt(n);
	tot=n/block;
	if(n%block) tot++;
	for(int i=1;i<=tot;i++){
		L[i]=(i-1)*block+1;
		R[i]=i*block;
	}
	R[tot]=n;
	for(int i=1;i<=n;i++){
		belong[i]=(i-1)/block+1;
	}
	for(int i=1;i<=tot;i++){
		sort(b+L[i],b+R[i]+1);
	}
}
void change(){
	if(belong[x]==belong[y]){
		for(int i=x;i<=y;i++){
			a[i]+=k;
		}
		for(int i=L[belong[x]];i<=R[belong[x]];i++){
			b[i]=a[i];
		}
		sort(b+L[belong[x]],b+R[belong[x]]+1);
	}
	else{
		for(int i=x;i<=R[belong[x]];i++) a[i]+=k;
		for(int i=L[belong[y]];i<=y;i++) a[i]+=k;
		for(int i=belong[x]+1;i<=belong[y]-1;i++){
			lazy[i]+=k;
		}
		for(int i=L[belong[x]];i<=R[belong[x]];i++) b[i]=a[i];
		for(int i=L[belong[y]];i<=R[belong[y]];i++) b[i]=a[i];
		sort(b+L[belong[x]],b+R[belong[x]]+1);
		sort(b+L[belong[y]],b+R[belong[y]]+1);
	}
}
void query(){
	if(belong[x]==belong[y]){
		for(int i=x;i<=y;i++){
			if(lazy[belong[x]]+a[i]>=k) ans++;
		}
		return;
	}
	else{
		for(int i=x;i<=R[belong[x]];i++){
			if(lazy[belong[x]]+a[i]>=k) ans++;
		}
		for(int i=L[belong[y]];i<=y;i++){
			if(lazy[belong[y]]+a[i]>=k) ans++;
		}
		for(int i=belong[x]+1;i<=belong[y]-1;i++){
			int l=L[i],r=R[i],temp=0;
			int mid=0;
			while(l<=r){
				mid=(l+r)>>1;
				if(b[mid]+lazy[i]>=k){
					r=mid-1;
					temp=R[i]-mid+1;
				}
				else{
					l=mid+1;
				}
			}
			ans+=temp;
		}
	}
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	init();
	while(q--){
		char c;
		cin>>c;
		scanf("%d%d%d",&x,&y,&k);
		if(c=='M'){
			change();
		}
		if(c=='A'){
			query();
			printf("%d\n",ans);
			ans=0;
		}
	}
}

ST

inline int query(int l, int r)
{
    int mid = log2(r - l + 1);
    return max(f[l][mid], f[r - (1 << mid) + 1][mid]);
}
int main()
{
	int n = read, m = read;
	for(int i = 1;i <= n;i ++ )
	{
		f[i][0] = read;
	}
	for(int j = 1;j <= (log(n) / log(2));j ++ ){
		for(int i = 1;i <= n - (1 << j) + 1;i ++ )
		{
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
		}
	}
	while(m -- )
	{
		cout << query(read, read) << endl;
	}
	return 0;
}

树套树

图论

拓扑排序

queue <int> Q;
void toposort() {
	for(int i = 1; i <= n; i++) {
		if(deg[i] == 0) {
			printf("%d ", i);
			Q.push(i);
		}
	}
	while(Q.size()) {
		int x = Q.front(); Q.pop();
		for(int i = Head[x]; i; i = Next[i]) {
			deg[to[i]]--;
			if(deg[to[i]] == 0) {
				printf("%d ", to[i]);
				Q.push(to[i]);
			}
		}
	}
}

最小生成树

prim

kruskal

次小生成树

最短路

dijkstra

前向星
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});

    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.second, distance = t.first;

        if (st[ver]) continue;
        st[ver] = true;

        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }

    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
vector
void dijkstra(int s)
{
    priority_queue<PII, vector<PII>, greater<PII> > q;
    q.push({0, s});
    memset(vis, false, sizeof(vis)), memset(dist, 0x3f, sizeof(dist));
    dist[s] = 0;
    while(q.size())
    {
        PII cur = q.top(); q.pop();
        int u = cur.second, w = cur.first;
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = 0;i < g[u].size();i ++ ){
            int v = g[u][i].first;
            if(dist[v] > dist[u] + g[u][i].second){
                dist[v] = dist[u] + g[u][i].second;
                q.push({dist[v], v});
            }
        }
    }
}

spfa

void spfa()
{
    memset(dist, 0x3f, sizeof dist);
    queue<int> q;
    q.push(1);
    dist[1] = 0;
    vis[1] = true;
    while(q.size()){
        int u = q.front(); q.pop();
//        cout << u << endl;
        vis[u] = false;
        for(int i = 0;i < g[u].size();i ++ ){
            int v = g[u][i].first, w = g[u][i].second;
            if(dist[v] > dist[u] + w){
                dist[v] = dist[u] + w;
                if(!vis[v]){
                    q.push(v); vis[v] = true;
                }
            }
        }
    }
}

floyd

void fl(){    
    for(int k=1;k<=n;k++){        
        for(int i=1;i<=n;i++){            
            for(int j=1;j<=n;j++)            
            {                
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);            
            }        
        }    
    }
}

最长路

spfa 建图时 c 变 -c;t 变 -t。

判负环

spfa

bool spfa()
{
    queue<int> q;
    for(int i = 1;i <= n;i ++ ){
        vis[i] = true;
        q.push(i);
    }
    while(q.size()){
        int u = q.front(); q.pop();
//        cout << u << endl;
        vis[u] = false;
        for(int i = 0;i < (int)g[u].size();i ++ ){
            int v = g[u][i].first, w = g[u][i].second;
            if(dist[v] > dist[u] + w){
                dist[v] = dist[u] + w;
                cnt[v] = cnt[u]  +1;
                if(cnt[v] >= n) return false;
                if(!vis[v]){
                    q.push(v); vis[v] = true;
                }
            }
        }
    }
    return true;
}

传递闭包

普通 floyd

for(int k = 1;k <= n;k ++ ){
    for(int i = 1;i <= n;i ++ ){
        for(int j = 1;j <= n;j ++ ){
             g[i][j] |= g[i][k] && g[k][j];
        }
    }
}

bitset 优化

bitset<N> g[N];
for(int k = 1;k <= n;k ++ ){
    for(int i = 1;i <= n;i ++ ){
        if(g[i][k]) g[i] |= g[k];
    }
}

差分约束

k 短路

tarjan 缩点

void tarjan(int u)
{
    low[u] = dfn[u] = ++t;
    vis[u] = true;
    st.push(u);
    for(int i = 0;i < g[u].size();i ++ ){
        int v = g[u][i];
        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[u])
    {
        cnt ++ ;
        int k;
        do
        {
            k = st.top(); st.pop();
            sum[cnt] += a[k];
            f[k] = cnt;
            vis[k] = false;
        }while(k != u);
    }
}
for(int i = 1;i <= n;i ++ ){
    if(!dfn[i]) tarjan(i);
}

for(int u = 1;u <= n;u ++ ){
    for(int i = 0;i < g[u].size();i ++ ){
        int v = g[u][i];
        if(f[v] != f[u]){
            g1[f[u]].push_back(f[v]);
        }
    }
}

最小环

dijkstra

floyd

网络流

分层图

备注:暂时还没怎么刷到这类题,先贴一道题吧。

[P4568 JLOI2011] 飞行路线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int inf = INT_MAX;
typedef pair<int, int> PII;

int n, m, k, s, t;
int d[N][11];
struct node
{
    int u, v;
};
vector<node> g[N];
bool vis[N];
void dijkstra()
{
    priority_queue<PII, vector<PII>, greater<PII> > q;
    for(int i = 0;i <= k;i ++ ) d[s][i] = 0;
    for(int i = 0;i <= k;i ++ )
    {
        q.push(make_pair(0, s));
        while(q.size())
        {
            int x = q.top().second; q.pop();
            if(vis[x]) continue;
            vis[x] = true;
            for(int j = 0;j < g[x].size();j ++ )
            {
                int y = g[x][j].u;
                int f = 0;
                if(i && d[y][i] > d[x][i - 1])
                {
                    d[y][i] = d[x][i - 1];
                    f = 1;
                }
                if(d[y][i] > d[x][i] + g[x][j].v)
                {
                    d[y][i] = d[x][i] + g[x][j].v;
                    f = 1;
                }
                if(f == 1) q.push(make_pair(d[y][i], y));
            }
            
        }
        memset(vis, false, sizeof(vis));
    }
}

int main(){
    cin >> n >> m >> k;
    cin >> s >> t;
    for(int i = 1;i <= m;i ++ )
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
    }
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j <= k;j ++ )
        {
            d[i][j] = inf;
        }
    }
    dijkstra();
    int ans = inf;
    for(int i = 0;i <= k;i ++ ) ans = min(ans, d[t][i]);
    cout << ans << endl;
    return 0;
}

树链剖分

仅给出区间的操作,如果更换更换线段树即可,见上。

struct Segment_Tree
{
	struct node
	{
		int l, r, sum, lazy;
	}tr[N << 2];
	void push_up(int u)
	{
		tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
	}
	void build(int u, int l, int r)
	{
		tr[u].l = l, tr[u].r = r;
		if(l == r){
			tr[u].sum = a[l]; tr[u].sum %= p;
			return ;
		}
		int mid = (l + r) >> 1;
		build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
		push_up(u);
	}
	void update(int u, int l, int r, int k)
    {
        if(l <= tr[u].l && tr[u].r <= r){
            tr[u].lazy += k;
            return ;
        }
        tr[u].sum += (min(r, tr[u].r) - max(l, tr[u].l) + 1) * k;
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l <= mid) update(u << 1, l, r, k);
        if(r >  mid) update(u << 1 | 1, l, r, k);
    }
	int query(int u, int l, int r)
	{
		if(l <= tr[u].l && tr[u].r <= r)
		{
			return (tr[u].sum + (tr[u].r - tr[u].l + 1) * tr[u].lazy) % p;
		}
		int res = (min(tr[u].r, r) - max(tr[u].l, l) + 1) * tr[u].lazy;
		int mid = (tr[u].l + tr[u].r) >> 1;
		if(l <= mid) res += query(u << 1, l, r);
		if(r >  mid) res += query(u << 1 | 1, l, r);
		return res % p;
	}
}seg;

struct TreePou
{
	void update(int x, int y, int val)
	{
		val %= p;
		while(top[x] != top[y]){
			if(dep[top[x]] < dep[top[y]]) swap(x, y);
			seg.update(1, id[top[x]], id[x], val);
			x = fa[top[x]];
		}
		if(dep[x] > dep[y]) swap(x, y);
		seg.update(1, id[x], id[y], val);
	}
	int query(int x, int y)
	{
		int ans = 0;
		while(top[x] != top[y]){
			if(dep[top[x]] < dep[top[y]]) swap(x, y);
			ans += seg.query(1, id[top[x]], id[x]);
			ans %= p;
			x = fa[top[x]];
		}
		if(dep[x] > dep[y]) swap(x, y);
		ans += seg.query(1, id[x], id[y]);
		return ans % p;	
	}
	void tupdate(int x, int y)
	{
		seg.update(1, id[x], id[x] + size[x] - 1, y);
	}
	int tquery(int x)
	{
		return seg.query(1, id[x], id[x] + size[x] - 1);
	}
}tp;

void dfs1(int u, int f, int deep)
{
    dep[u] = deep;
    fa[u] = f;
    size[u] = 1;
    int maxn = -1;
    for(int i = 0;i < g[u].size();i ++ )
    {
        int v = g[u][i];
        if(v == f) continue;
        dfs1(v, u, deep + 1);
        size[u] += size[v];
        if(size[v] > maxn) {
            maxn = size[v];
            son[u] = v;
        }
    }
}

void dfs2(int u, int topfa)
{
    id[u] = ++cnt;
    top[u] = topfa;
    a[cnt] = w[u];
    if(!son[u]) return ;
    dfs2(son[u], topfa);
    for(int i = 0;i < g[u].size();i ++ ){
        int v = g[u][i];
        if(v == fa[u] || v == son[u]){
            continue;
        }
        dfs2(v, v);
    }
}

LCA

倍增

void dfs(int u, int fa)
{
	dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	for(int i = 1;(1 << i) <= dep[u];i ++ )
	{
		f[u][i] = f[f[u][i - 1]][i - 1];
	}
	for(int i = 0;i < g[u].size();i ++){
		int v = g[u][i];
		if(v == fa) continue;
		f[v][0] = u;
		dfs(v, u);
		
	} 
}

int LCA(int x, int y)
{
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 20;i >= 0;i -- )
	{
		if(dep[f[x][i]] >= dep[y]){
			x = f[x][i];
		}
	}
	if(x == y) return x;
	for(int i = 20;i >= 0;i -- )
	{
		if(f[x][i] != f[y][i]){
			x = f[x][i], y = f[y][i];
		}
	}
	return f[x][0];
}

树链剖分

void dfs1(int u, int f, int deep)
{
    dep[u] = deep;
    fa[u] = f;
    size[u] = 1;
    int maxn = -1;
    for(int i = 0;i < g[u].size();i ++ )
    {
        int v = g[u][i];
        if(v == f) continue;
        dfs1(v, u, deep + 1);
        size[u] += size[v];
        if(size[v] > maxn) {
            maxn = size[v];
            son[u] = v;
        }
    }
}

void dfs2(int u, int topfa)
{
    id[u] = ++cnt;
    top[u] = topfa;
    a[cnt] = w[u];
    if(!son[u]) return ;
    dfs2(son[u], topfa);
    for(int i = 0;i < g[u].size();i ++ ){
        int v = g[u][i];
        if(v == fa[u] || v == son[u]){
            continue;
        }
        dfs2(v, v);
    }
}
int LCA(int x,int y)
{
	while(top[x] != top[y]){
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y]) return y;
	return x;
}

树的重心

树的直径

树上计数

树的点分治

杂项

IO

#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
namespace IO
{
    template<typename T>
    inline T read(T x)
    {
        T opt = 1, sum = 0;
        char ch = getchar();
        while(!isdigit(ch)) opt = (ch == '-') ? -1 : 1, ch = getchar();
        while( isdigit(ch)) sum = (sum << 1) + (sum << 3) + (ch ^ 48), ch = getchar();
        return opt * sum;
    }
}
#define read IO::read(0)
inline void put(int x)
{
    if (x > 9) put(x / 10);
    putchar(x % 10 + 48);
}

二分

三分

根号分治

模拟退火

备注

更新日志

Update 2024.7.18 建立文档

Update 2024.7.19 优化排版 + 更新dijkstra / lca

posted @ 2024-03-03 21:10  浮光流年  阅读(9)  评论(0编辑  收藏  举报