模板-树链剖分

#define MAXN 50010  
#define L(u) (u<<1)  
#define R(u) (u<<1|1)  
  
//写在类里面爆栈  
int n, m, q;  
int tim;       //时间戳  
int num[MAXN]; //树上每个节点的初始值  
int siz[MAXN]; //siz[u]表示以u为根的子树的节点数  
int top[MAXN]; //树链上深度最小的点  
int son[MAXN]; //重儿子  
int dep[MAXN]; //深度  
int tid[MAXN]; //节点的时间戳  
int _tid[MAXN]; //tid[i]=j表示时间戳为i的节点是j  
int father[MAXN]; //父节点  
bool vis[MAXN];  
vector<int> edge[MAXN];  
  
void init(int n)  
{  
    for(int i = 1; i <= n; i++)  
    {  
        siz[i] = top[i] = son[i] = 0;  
        dep[i] = tid[i] = _tid[i] = father[i] = 0;  
        vis[i] = false;  
        tim = 0; //时间戳  
        edge[i].clear();  
    }  
}  
  
void addedge(int u, int v) //无根树加双向边  
{  
    edge[u].push_back(v);  
    edge[v].push_back(u);  
}  
  
//树链剖分  dfs1(1,0)
void dfs1(int u, int pre)  
{  
    vis[u] = true;  
    siz[u] = 1;  
    father[u] = pre;  
    dep[u] = dep[pre] + 1; //注意根节点比较特殊  
    int sz = edge[u].size();  
    for(int i = 0; i < sz; i++)  
    {  
        int v = edge[u][i];  
        if(v != father[u] && vis[v] == false)  
        {  
            dfs1(v, u);  
            siz[u] += siz[v];  
            if(son[u] == 0) son[u] = v;  
            else if(siz[son[u]] < siz[v]) son[u] = v;  
        }  
    }  
}  
  //注意清空vis,dfs2(1,1)
void dfs2(int u, int tp)  
{  
    vis[u] = true;  
    tid[u] = ++tim;  
    _tid[tim] = u;  
    top[u] = tp;  
    if(son[u] != 0)  
        dfs2(son[u], tp); //同一条重链的顶部相同  
  
    int sz = edge[u].size();  
    for(int i = 0; i < sz; i++)  
    {  
        int v = edge[u][i];  
        if(v != father[u] && v != son[u] && vis[v] == false) //注意去掉重儿子  
            dfs2(v, v);  
    }  
}  
  
void update(int u, int l, int r, int v); //线段树的更新函数  
  
void change(int x, int y, int val)  
{  
    while(top[x] != top[y])  
    {  
        if(dep[top[x]] < dep[top[y]])  
            swap(x, y);  
        update(1, tid[top[x]], tid[x], val); //dfs2时顶部先访问,故tid[top]较小  
        x = father[top[x]]; //因为top[x]->x路径上的所有点已经被更新了  
    }  
  
    if(dep[x] > dep[y]) //同一条重链上深度小的tid小  
        swap(x, y);  
    update(1, tid[x], tid[y], val);  
}  
  
  
//线段树部分  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值