首页 > 其他 > 详细

树链剖分学习笔记

时间:2019-09-13 20:31:24      阅读:77      评论:0      收藏:0      [点我收藏+]

 

因为抄模板抄错(...),来来回回看了很多遍板子,debug了好久。感觉理解得很到位了。不存在的。

 

洛谷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\n",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\n",query(1,tid[u],tid[u]+siz[u]-1)%mod);
        }
    }
}

 

树链剖分学习笔记

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

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!