树链剖分模板

代码

//input(输入是先输N,再输N-1条边带权),调用dfs和Div,然后建线段树,更新每个点的值
//Find用于找两个点之间的最大值或其他,Update用于单点更新,如果成段更新于Find写得类似
#define tu nod[u]
#define tv nod[v]
#define e tree[id]
#define lson tree[id*2]
#define rson tree[id*2+1]
int N;
struct node{ int top,fa,deep,s,p,fp,son; };
struct edge
{
    int u,v,c;
    edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){}
}E[maxn];
struct Tree{ int le,ri,v; };
struct DivTree
{
    int pid;
    vector<int> G[maxn];
    node nod[maxn];
    Tree tree[4*maxn];
    void init()
    {
        pid=0;
        for(int i=0;i<maxn;i++) G[i].clear(),nod[i].son=-1; //初始化
    }
    void dfs(int u,int fa,int deep)
    {
        tu.fa=fa,tu.deep=deep,tu.s=1;  //保存父节点,深度,大小为1
        int Size=G[u].size();
        for(int i=0;i<Size;i++)
        {
            int v=G[u][i];
            if(v==fa) continue;  //父亲不管
            dfs(v,u,deep+1);
            tu.s+=tv.s;  //加上大小
            if(tu.son==-1||tv.s>nod[tu.son].s) tu.son=v; //找重链所指向的点
        }
    }
    void Div(int u,int top)
    {
        tu.top=top;  //重链顶点
        tu.p=++pid;  //重新编号
        nod[tu.p].fp=u;
        if(tu.son!=-1) Div(tu.son,top); //有重链继续往下找
        else return;
        int Size=G[u].size();
        for(int i=0;i<Size;i++)
        {
            int v=G[u][i];
            if(v==tu.fa||v==tu.son) continue;
            Div(v,v); //新的重链
        }
    }
    void pushup(int id){ e.v=max(lson.v,rson.v); }
    void Build_tree(int id,int le,int ri)
    {
        e.le=le,e.ri=ri,e.v=0;
        if(le==ri) return;
        int mid=(le+ri)/2;
        Build_tree(id*2,le,mid);
        Build_tree(id*2+1,mid+1,ri);
    }
    void Update(int id,int k,int v)
    {
        int le=e.le,ri=e.ri;
        if(le==ri){ e.v=v; return; }
        int mid=(le+ri)/2;
        if(k<=mid) Update(id*2,k,v);
        else Update(id*2+1,k,v);
        pushup(id);
    }
    int Query(int id,int x,int y)
    {
        int le=e.le,ri=e.ri;
        if(x<=le&&ri<=y) return e.v;
        int mid=(le+ri)/2;
        int ret=0;
        if(x<=mid) ret=max(ret,Query(id*2,x,y));
        if(y>mid)  ret=max(ret,Query(id*2+1,x,y));
        return ret;
    }
    int Find(int u,int v)
    {
        int f1=tu.top,f2=tv.top;
        int ret=0;
        while(f1!=f2) //不在同一条链上
        {
            if(nod[f1].deep<nod[f2].deep)  //总是让u是深度大的点
            {
                swap(f1,f2);
                swap(u,v);
            }
            ret=max(ret,Query(1,nod[f1].p,tu.p));  //查询这条链
            u=nod[f1].fa; f1=tu.top;   //跳到父节点去
        }
        if(u==v) return ret;  //相同
        if(tu.deep>tv.deep) swap(u,v);
        ret=max(ret,Query(1,nod[tu.son].p,tv.p)); //查询同一条链上的这段区间
        return ret;
    }
    void input() //输入是输入一个N,再输入N-1条带权边
    {
        scanf("%d",&N);
        init();
        for(int i=1;i<N;i++)
        {
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            E[i]=edge(u,v,c);   //
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,0,0);
        Div(1,1);
        Build_tree(1,1,pid); //建树
        for(int i=1;i<N;i++)
        {
            edge& t=E[i];
            int& u=t.u;
            int& v=t.v;
            if(tu.deep>tv.deep) swap(u,v);
            Update(1,tv.p,t.c);   //修改边权,偏向v
        }
    }
};
View Code
原文地址:https://www.cnblogs.com/wust-ouyangli/p/5759571.html