【树】树链剖分学习笔记

隔了俩月,有点看不明白这个模板Σ(っ °Д °;)っ  然后就再看了一遍.....

需要注意的是:

一个节点x所在重链的顶端 即 top[x],与x之间的那条链的所有节点 的dfs序是连续的

所以如果节点x的父亲节点fa与x的dfs序 不连续,则top[x]=x

因为 dfs序是以重链为优先确定的。

所以根据重链可以保证线段树区间的连续性和正确性  


洛谷P3384树链剖分

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int maxn=2e5+50;

vector<int>p[maxn];
int val[maxn],mod;


int siz[maxn],dep[maxn],fad[maxn],son[maxn];
int top[maxn],tid[maxn],rnk[maxn],cnt;
/*
siz[i] 保存以i为根的树的大小
dep[i]  i节点的深度
fad[i]  i的父亲
son[i]  i的重儿子
top[i]  重链的顶端节点
tid[i]  i的新编号(dfs) 
rnk[i]  rnk[tid[i]]=i
*/
inline void dfs1(int u,int fa,int d)
{
    /*
    u  当前节点 
    fa  父亲 
    d  深度 
    */
    dep[u]=d;
    fad[u]=fa;
    siz[u]=1;
    
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v==fa)continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}

inline void dfs2(int u,int t)
{
    /*
    u  当前节点 
    t  顶端重节点 
    */
    top[u]=t;
    tid[u]=++cnt;
    rnk[cnt]=u; 
    if(!son[u])return;//当前节点不在重链上
    dfs2(son[u],t);
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
    }
}

struct kkk{
    int l,r;ll sum,la;
}tree[maxn<<2];

inline void build(int k,int l,int r)
{
    tree[k].l=l;tree[k].r=r;
    if(l==r)
    {
        tree[k].sum=val[rnk[l]]%mod;
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%mod;
}
inline void down(int k)
{
    tree[k<<1].sum=(tree[k<<1].sum+(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la)%mod;
    tree[k<<1|1].sum=(tree[k<<1|1].sum+(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la)%mod;
    tree[k<<1].la=(tree[k<<1].la+tree[k].la)%mod;
    tree[k<<1|1].la=(tree[k<<1|1].la+tree[k].la)%mod;
    tree[k].la=0;
}
inline void add(int k,int l,int r,ll w)
{
    if(l<=tree[k].l&&tree[k].r<=r)
    {
        tree[k].la=(tree[k].la+w)%mod;
        tree[k].sum=(tree[k].sum+(tree[k].r-tree[k].l+1)*w)%mod;
        return;
    }
    if(tree[k].la)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<=mid)add(k<<1,l,r,w);
    if(r>mid)add(k<<1|1,l,r,w);
    tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%mod;
}
inline int query(int k,int l,int r)
{
    if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
    if(tree[k].la)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    ll ans=0;
    if(l<=mid)ans=(ans+query(k<<1,l,r))%mod;
    if(r>mid)ans=(ans+query(k<<1|1,l,r))%mod;
    return ans;
}
inline void addline(int x,int y,ll w)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        add(1,tid[top[x]],tid[x],w);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    add(1,tid[x],tid[y],w);
}
inline int calline(int x,int y)
{
    ll ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=(ans+query(1,tid[top[x]],tid[x]))%mod;
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=(ans+query(1,tid[x],tid[y]))%mod;
    return ans;
}

int main()
{
    int n,m,G,i,u,v,w,op;
    scanf("%d%d%d%d",&n,&m,&G,&mod);
    for(i=1;i<=n;i++)scanf("%d",&val[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        p[u].push_back(v);
        p[v].push_back(u);
    }
//    memset(siz,0,sizeof(siz));
    memset(son,0,sizeof(son));
    dfs1(G,0,1);
    dfs2(G,G);
    build(1,1,n);
    while(m--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%d",&u,&v,&w);
            addline(u,v,w%mod);
        }
        else if(op==2)
        {
            scanf("%d%d",&u,&v);
            printf("%d
",calline(u,v)%mod);
        }
        else if(op==3)
        {
            scanf("%d%d",&u,&w);
            add(1,tid[u],tid[u]+siz[u]-1,w%mod);
        }
        else if(op==4)
        {
            scanf("%d",&u);
            printf("%d
",query(1,tid[u],tid[u]+siz[u]-1)%mod);
        }
    }
}

L. Subway Lines

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int maxn=2e5+50;

vector<int>p[maxn];


int siz[maxn],dep[maxn],fad[maxn],son[maxn];
int top[maxn],tid[maxn],rnk[maxn],cnt;
/*
siz[i] 保存以i为根的树的大小
dep[i]  i节点的深度
fad[i]  i的父亲
son[i]  i的重儿子
top[i]  重链的顶端节点
tid[i]  i的新编号(dfs) 
rnk[i]  rnk[tid[i]]=i
*/
inline void dfs1(int u,int fa,int d)
{
    /*
    u  当前节点 
    fa  父亲 
    d  深度 
    */
    dep[u]=d;
    fad[u]=fa;
    siz[u]=1;
    
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v==fa)continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}

inline void dfs2(int u,int t)
{
    /*
    u  当前节点 
    t  顶端重节点 
    */
    top[u]=t;
    tid[u]=++cnt;
    rnk[cnt]=u; 
    if(!son[u])return;//当前节点不在重链上
    dfs2(son[u],t);
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
    }
}

struct kkk{
    int l,r,sum,la;
}tree[maxn<<2];

inline void build(int k,int l,int r)
{
    tree[k].l=l;tree[k].r=r;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
inline void down(int k)
{
    tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la;
    tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la;
    tree[k<<1].la+=tree[k].la;
    tree[k<<1|1].la+=tree[k].la;
    tree[k].la=0;
}
inline void add(int k,int l,int r,ll w)
{
    if(l<=tree[k].l&&tree[k].r<=r)
    {
        tree[k].la+=w;
        tree[k].sum+=(tree[k].r-tree[k].l+1)*w;
        return;
    }
    if(tree[k].la)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<=mid)add(k<<1,l,r,w);
    if(r>mid)add(k<<1|1,l,r,w);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
inline int query(int k,int l,int r)
{
    if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
    if(tree[k].la)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    int ans=0;
    if(l<=mid)ans+=query(k<<1,l,r);
    if(r>mid)ans+=query(k<<1|1,l,r);
    return ans;
}
inline void addline(int x,int y,int w)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        add(1,tid[top[x]],tid[x],w);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    add(1,tid[x],tid[y],w);
}
inline int calline(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=query(1,tid[top[x]],tid[x]);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans+=query(1,tid[x],tid[y]);
    return ans;
}

int main()
{
    int n,q,i,u,v,x,y;
    scanf("%d%d",&n,&q);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        p[u].push_back(v);
        p[v].push_back(u);
    }
    memset(son,0,sizeof(son));
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    while(q--)
    {
        scanf("%d%d%d%d",&u,&v,&x,&y);
        addline(u,v,1);
        printf("%d
",calline(x,y));
        addline(u,v,-1);
    }
}

洛谷P2420

因为不太会处理边权,所以干脆把边权设成一个点,点权为边权,连接点的点权就为0 。

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int maxn=2e5+50;


vector<int>p[maxn];
int val[maxn]; 


int siz[maxn],dep[maxn],fad[maxn],son[maxn];
int top[maxn],tid[maxn],rnk[maxn],cnt;
/*
siz[i] 保存以i为根的树的大小
dep[i]  i节点的深度
fad[i]  i的父亲
son[i]  i的重儿子
top[i]  重链的顶端节点
tid[i]  i的新编号(dfs) 
rnk[i]  rnk[tid[i]]=i
*/
inline void dfs1(int u,int fa,int d)
{
    /*
    u  当前节点 
    fa  父亲 
    d  深度 
    */
    dep[u]=d;
    fad[u]=fa;
    siz[u]=1;
    
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v==fa)continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}

inline void dfs2(int u,int t)
{
    /*
    u  当前节点 
    t  顶端重节点 
    */
    top[u]=t;
    tid[u]=++cnt;
    rnk[cnt]=u; 
    if(!son[u])return;//当前节点不在重链上
    dfs2(son[u],t);
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
    }
}

struct kkk{
    int l,r,sum,la;
}tree[maxn<<2];

inline void build(int k,int l,int r)
{
    tree[k].l=l;tree[k].r=r;
    if(l==r)
    {
        tree[k].sum=val[rnk[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k].sum=tree[k<<1].sum^tree[k<<1|1].sum;
}
inline int query(int k,int l,int r)
{
    if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
    int mid=(tree[k].l+tree[k].r)>>1;
    int ans=0;
    if(l<=mid)ans^=query(k<<1,l,r);
    if(r>mid)ans^=query(k<<1|1,l,r);
    return ans;
}
inline int calline(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans^=query(1,tid[top[x]],tid[x]);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans^=query(1,tid[x],tid[y]);
    return ans;
}

int main()
{
    int n,m,i,u,v,w,tot;
    scanf("%d",&n);
    tot=n;
    for(i=1;i<n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        p[u].push_back(++tot);
        p[tot].push_back(u);
        p[v].push_back(tot);
        p[tot].push_back(v);
        val[u]=0;val[v]=0;
        val[tot]=w;
    }
    memset(son,0,sizeof(son));
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,tot);
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d%d",&u,&v);
        printf("%d
",calline(u,v));
    }
}

洛谷P3258

#include<bits/stdc++.h>
#define debug printf("!");
using namespace std;
typedef long long ll;
const int maxn=3e5+50;


vector<int>p[maxn];


int siz[maxn],dep[maxn],fad[maxn],son[maxn];
int top[maxn],tid[maxn],rnk[maxn],cnt;
/*
siz[i] 保存以i为根的树的大小
dep[i]  i节点的深度
fad[i]  i的父亲
son[i]  i的重儿子
top[i]  重链的顶端节点
tid[i]  i的新编号(dfs) 
rnk[i]  rnk[tid[i]]=i
*/
inline void dfs1(int u,int fa,int d)
{
    /*
    u  当前节点 
    fa  父亲 
    d  深度 
    */
    dep[u]=d;
    fad[u]=fa;
    siz[u]=1;
    
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v==fa)continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}

inline void dfs2(int u,int t)
{
    /*
    u  当前节点 
    t  顶端重节点 
    */
    top[u]=t;
    tid[u]=++cnt;
    rnk[cnt]=u; 
    if(!son[u])return;//当前节点不在重链上
    dfs2(son[u],t);
    for(int i=0;i<p[u].size();i++)
    {
        int v=p[u][i];
        if(v!=son[u]&&v!=fad[u])dfs2(v,v);//非重节点的top是自己 
    }
}

struct kkk{
    int l,r,sum,la;
}tree[maxn<<2];

inline void build(int k,int l,int r)
{
    tree[k].l=l;tree[k].r=r;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
}
inline void down(int k)
{
    tree[k<<1].sum+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].la;
    tree[k<<1|1].sum+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].la;
    tree[k<<1].la+=tree[k].la;
    tree[k<<1|1].la+=tree[k].la;
    tree[k].la=0;
}
inline void add(int k,int l,int r,ll w)
{
    if(l<=tree[k].l&&tree[k].r<=r)
    {
        tree[k].la+=w;
        tree[k].sum+=(tree[k].r-tree[k].l+1)*w;
        return;
    }
    if(tree[k].la)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    if(l<=mid)add(k<<1,l,r,w);
    if(r>mid)add(k<<1|1,l,r,w);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
inline int query(int k,int l,int r)
{
    if(l<=tree[k].l&&tree[k].r<=r)return tree[k].sum;
    if(tree[k].la)down(k);
    int mid=(tree[k].l+tree[k].r)>>1;
    int ans=0;
    if(l<=mid)ans+=query(k<<1,l,r);
    if(r>mid)ans+=query(k<<1|1,l,r);
    return ans;
}
inline void addline(int x,int y,int w)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        add(1,tid[top[x]],tid[x],w);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    add(1,tid[x],tid[y],w);
}
inline int calline(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=query(1,tid[top[x]],tid[x]);
        x=fad[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans+=query(1,tid[x],tid[y]);
    return ans;
}

int main()
{
    int n,i,u,v,w,a[maxn],ans;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        p[u].push_back(v);
        p[v].push_back(u);
    }
    memset(son,0,sizeof(son));
    dfs1(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    addline(a[1],a[2],1);
    for(i=2;i<n;i++)
    {
        addline(a[i],a[i+1],1);
        add(1,tid[a[i]],tid[a[i]],-1);
    }
    add(1,tid[a[n]],tid[a[n]],-1);
    for(i=1;i<=n;i++)printf("%d
",query(1,tid[i],tid[i]));
}

原文地址:https://www.cnblogs.com/kkkek/p/11517481.html