树链剖分(剖链模板)

1.前向星型模板

/*
重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
轻儿子:v的其它子节点。
重边:点v与其重儿子的连边。
轻边:点v与其轻儿子的连边。
重链:由重边连成的路径。
轻链:轻边。
*/const int MAXN = 50000+10;
struct node
{
    int to, next;
    node(){
    }
    node(int to, int next) : to(to), next(next){
    }
}edge[2*MAXN];
int head[MAXN], alledge;
void init()
{
    memset(head, 0xff, sizeof(head));
    alledge = 0;
}
void addedge(int x, int y)
{
    edge[alledge] = node(y, head[x]);
    head[x] = alledge++;
    edge[alledge] = node(x, head[y]);
    head[y] = alledge++;
}
int a[MAXN];//点权值
int siz[MAXN];//siz[v]表示以v为根的子树的节点数(包含自身结点)
int dep[MAXN];//dep[v]表示v的深度(根深度为1)
int fa[MAXN];//fa[v]表示v的父亲
int son[MAXN];//son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子)
int top[MAXN];//top[v]表示v所在的链的顶端节点
int w[MAXN];//w[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置
int totw;
void init_treelist()
{
    memset(son, 0xff, sizeof(son));// son[v]为 -1 表示重儿子不存在 
    memset(top, 0xff, sizeof(top));
    totw = 0; 
}
void dfs_1(int id, int pr, int deep)//求 fa、dep、siz、son、top
{
    fa[id] = pr; dep[id] = deep; siz[id] = 1;
    int s = -1, ii = -1;
    for(int i = head[id]; ~i; i = edge[i].next)
    {
        int to = edge[i].to;
        if(to == pr) continue;
        dfs_1(to, id, deep+1);
        siz[id] += siz[to];
        if(siz[to] > s)
        {
            s = siz[to];
            ii = to;
        }
    }
    son[id] = ii;
}
void dfs_2(int id, int pr)//求 w
{
     w[id] = ++totw;
     if(top[id]==-1) top[id] = id;
     if(~son[id])
     {
         top[son[id]] = top[id];
         dfs_2(son[id], id);
     }
    for(int i = head[id]; ~i; i = edge[i].next)
    {
        int to = edge[i].to;
         if(to == pr) continue;
         if(to == son[id]) continue;
         dfs_2(to, id);
    }
}
void update(int x, int y, int k)
{
    int fx = top[x], fy = top[y];
    while(fx != fy)
    {
        if(dep[fx] < dep[fy])
        {
            swap(fx, fy);
            swap(x, y);
        }
        //update(1, 1, n, w[fx], w[x], k); 线段树更新 
        x = fa[fx]; fx = top[x];
    }
    if(dep[x] < dep[y])
    {
        swap(x, y);
    }
    //update(1, 1, n, w[y], w[x], k); 线段树更新
}
int main (void)
{
    /*
    建图 
    */ 
    dfs_1(1, -1, 1);
    dfs_2(1, -1); 
} 

顺附 codefroces 343D -  Water Tree AC代码

/*
重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
轻儿子:v的其它子节点。
重边:点v与其重儿子的连边。
轻边:点v与其轻儿子的连边。
重链:由重边连成的路径。
轻链:轻边。
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 500000+10;
int n; 
struct node
{
    int to, next;
    node(){
    }
    node(int to, int next) : to(to), next(next){
    }
}edge[2*MAXN];
int head[MAXN], alledge;
void init()
{
    memset(head, 0xff, sizeof(head));
    alledge = 0;
}
void addedge(int x, int y)
{
    edge[alledge] = node(y, head[x]);
    head[x] = alledge++;
    edge[alledge] = node(x, head[y]);
    head[y] = alledge++;
}
int siz[MAXN];//siz[v]表示以v为根的子树的节点数(包含自身结点)
int dep[MAXN];//dep[v]表示v的深度(根深度为1)
int fa[MAXN];//fa[v]表示v的父亲
int son[MAXN];//son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子)
int top[MAXN];//top[v]表示v所在的链的顶端节点
int w[MAXN];//w[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置
int End[MAXN], END;
int totw;
void init_treelist()
{
    memset(son, 0xff, sizeof(son));// son[v]为 -1 表示重儿子不存在
    memset(top, 0xff, sizeof(top));
    totw = 0;
}
void dfs_1(int id, int pr, int deep)//求 fa、dep、siz、son、top
{
    fa[id] = pr; dep[id] = deep; siz[id] = 1;
    int s = -1, ii = -1;
    for(int i = head[id]; ~i; i = edge[i].next)
    {
        int to = edge[i].to;
        if(to == pr) continue;
        dfs_1(to, id, deep+1);
        siz[id] += siz[to];
        if(siz[to] > s)
        {
            s = siz[to];
            ii = to;
        }
    }
    son[id] = ii;
}
void dfs_2(int id, int pr)//求 w
{
     w[id] = ++totw;
     END = id;
     if(top[id]==-1) top[id] = id;
     if(~son[id])
     {
         top[son[id]] = top[id];
         dfs_2(son[id], id);
     }
    for(int i = head[id]; ~i; i = edge[i].next)
    {
        int to = edge[i].to;
         if(to == pr) continue;
         if(to == son[id]) continue;
         dfs_2(to, id);
    }
    End[id] = END;
}

struct treenode
{
    int v;
    int flag;
}tree[MAXN<<2];
void bulid_tree()
{
    memset(tree, 0x00, sizeof(tree));
}
void push_down(int id)
{
    tree[id<<1].flag = tree[id].flag;
    tree[(id<<1)|1].flag = tree[id].flag;
    tree[id].flag = 0;
}
void update(int id, int l, int r, int left, int right, int k)
{
    if(l==left && r==right)
    {
        if(k==0) tree[id].flag = -1;
        if(k==1) tree[id].flag = 1;
        if(l==r) tree[id].v = k;
        return ;
    }
    int mid = l+r>>1;
    if( tree[id].flag ) push_down(id);
    if(right <= mid)
    {
        update(id<<1, l, mid, left, right, k);
    }
    else if(left > mid)
    {
        update((id<<1)|1, mid+1, r, left, right, k);
    }
    else
    {
        update(id<<1, l, mid, left, mid, k);
        update((id<<1)|1, mid+1, r, mid+1, right, k);
    }
}
int query(int id, int l, int r, int index)
{
    if(tree[id].flag == -1) return 0;
    if(tree[id].flag == 1) return 1;
    if(l==r&& r==index) return tree[id].v;
    int mid = l+r>>1;
    if(index <= mid) return query(id<<1, l, mid, index);
    return query((id<<1)|1, mid+1, r, index);
}
void update(int x, int y, int k)
{
    int fx = top[x], fy = top[y];
    while(fx != fy)
    {
        if(dep[fx] < dep[fy])
        {
            swap(fx, fy);
            swap(x, y);
        }
        update(1, 1, n, w[fx], w[x], k);
        x = fa[fx]; fx = top[x];
    }
    if(dep[x] < dep[y])
    {
        swap(x, y);
    }
    update(1, 1, n, w[y], w[x], k);
}
int main (void)
{
    ios::sync_with_stdio(false);
    init();
    init_treelist();
    cin >> n;
    for(int i = 1; i < n; ++i)
    {
        int x, y;
        cin >> x >> y;
        addedge(x, y);
    }
    dfs_1(1, -1, 1);
    dfs_2(1, -1);
    int q; cin >> q;
    while(q--)
    {
        int c, x; cin >> c >> x;
        switch( c )
        {
            case 1: update(1, 1, n, w[x], w[End[x]], 1); break;
            case 2: update(1, x, 0); break;
            default : cout << query(1, 1, n, w[x]) << endl; break;
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lkcc/p/7701634.html