树链剖分

What?

             熟练泼粪这又是一种十分神奇的数据结构,由于博主认为自身实力不行,所以不敢随便BB,上一个大佬级别的链接,超级清楚!Problem

不随便BB(既然不能随便BB,那只好不随便了)

依本博主看,树链剖分就是将一棵漂亮的树,解剖成一条条树链,然后使用线段树进行维护,从而解决一系列问题。

只要理解了树链剖分中各种新有名词的含义及特点,那么树链剖分便十分的简单。

有同学说:“什么?用线段树维护,那不是很变态?”没错,不过线段树算什么?引某位大佬早上对我说的一句话:“我们要把线段树当成STL来用。”%%%

Code

本博主由于懒,所以没打链式前向星(其实是不会啊),不过vector真好用啊。

#include<cstdio>
#include<vector>
#include<algorithm>
#define MAXN 100010
#define UD unsigned
using namespace std;

int n,m,r,Mod,cnt,ans;
int init[MAXN],cor[MAXN];
UD sl[MAXN];
vector<int> rel[MAXN];
struct CHAIN
{
    int id;
    int fa;
    int zhi;
    int size;
    int deep;
    int Max_son;
    int top;
}chain[MAXN];
struct TREE
{
    int l,r;
    int zhi;
    int lazy;
}tree[MAXN*8];

void Pushdown(int k)
{
    tree[k<<1].zhi+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].lazy;
    tree[k<<1].zhi%=Mod; 
    tree[k<<1].lazy+=tree[k].lazy;
    tree[k<<1].lazy%=Mod;
    tree[k<<1|1].zhi+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].lazy;
    tree[k<<1|1].zhi%=Mod;
    tree[k<<1|1].lazy+=tree[k].lazy;
    tree[k<<1|1].lazy%=Mod;
    tree[k].lazy=0;
}

void Build(int L,int R,int k)
{
    int Mid=(L+R)>>1;
    tree[k].l=L,tree[k].r=R;
    if(L==R)
    {
        tree[k].zhi=chain[cor[L]].zhi%=Mod;
        return;
    }
    Build(L,Mid,k<<1);
    Build(Mid+1,R,k<<1|1);
    tree[k].zhi=tree[k<<1].zhi+tree[k<<1|1].zhi;
    tree[k].zhi%=Mod;
}

void Update(int L,int R,int k,int s,int t,int x)
{
    int Mid=(L+R)>>1;
    Pushdown(k);
    if(s<=L && R<=t)
    {
        tree[k].zhi+=(tree[k].r-tree[k].l+1)*x;
        tree[k].lazy+=x;
        tree[k].zhi%=Mod;
        tree[k].lazy%=Mod;
        return;
    }
    if(s<=Mid)
        Update(L,Mid,k<<1,s,t,x);
    if(Mid<t)
        Update(Mid+1,R,k<<1|1,s,t,x);
    tree[k].zhi=tree[k<<1].zhi+tree[k<<1|1].zhi;
    tree[k].zhi%=Mod;
}

void Query(int L,int R,int k,int s,int t)
{
    int Mid=(L+R)>>1;
    Pushdown(k);
    if(s<=L && R<=t)
    {
        ans+=tree[k].zhi;
        ans%=Mod;
        return;
    }
    if(s<=Mid)
        Query(L,Mid,k<<1,s,t);
    if(Mid<t)
        Query(Mid+1,R,k<<1|1,s,t);
        
}

void Dfs1(int x,int f,int dep)
{
    int MAX=0;
    chain[x].fa=f,chain[x].deep=dep,chain[x].size=1,chain[x].zhi=init[x]%=Mod;
    for(UD i=0;i<sl[x];i++)
    {
        if(rel[x][i]==chain[x].fa)
            continue;
        Dfs1(rel[x][i],x,dep+1);
        if(chain[rel[x][i]].size>MAX)
            MAX=chain[rel[x][i]].size,chain[x].Max_son=rel[x][i];
        chain[x].size+=chain[rel[x][i]].size;
    }
}

void Dfs2(int x,int topf)
{
    chain[x].id=++cnt;
    cor[cnt]=x,chain[x].top=topf;
    if(!chain[x].Max_son)
        return;
    Dfs2(chain[x].Max_son,topf);
    for(UD i=0;i<sl[x];i++)
    {
        if(rel[x][i]==chain[x].fa || rel[x][i]==chain[x].Max_son)
            continue;
        Dfs2(rel[x][i],rel[x][i]);
    }
}

void Update_chain(int x,int y,int z)
{
    while(chain[x].top!=chain[y].top)
    {
        if(chain[chain[x].top].deep<chain[chain[y].top].deep)
            swap(x,y);
        Update(1,n,1,chain[chain[x].top].id,chain[x].id,z);
        x=chain[chain[x].top].fa;
    }
    if(chain[x].deep>chain[y].deep)
        swap(x,y);
    Update(1,n,1,chain[x].id,chain[y].id,z);
}

void Query_chain(int x,int y)
{
    ans=0;
    while(chain[x].top!=chain[y].top)
    {
        if(chain[chain[x].top].deep<chain[chain[y].top].deep)
            swap(x,y);
        Query(1,n,1,chain[chain[x].top].id,chain[x].id);
        x=chain[chain[x].top].fa;
    }
    if(chain[x].deep>chain[y].deep)
        swap(x,y);
    Query(1,n,1,chain[x].id,chain[y].id);
}

void Update_tree(int x,int z)
<%Update(1,n,1,chain[x].id,chain[x].id+chain[x].size-1,z);%>

void Query_tree(int x)
{
    ans=0;
    Query(1,n,1,chain[x].id,chain[x].id+chain[x].size-1);
}

int main()
{
    int opt,x,y,z;
    scanf("%d%d%d%d",&n,&m,&r,&Mod);
    for(int i=1;i<=n;i++)
        scanf("%d",&init[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        rel[x].push_back(y);
        rel[y].push_back(x);  
    }
    for(int i=1;i<=n;i++)
        sl[i]=rel[i].size();
    Dfs1(r,0,1);
    Dfs2(r,r);
    Build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            Update_chain(x,y,z);
        }
        if(opt==2)
        {
            scanf("%d%d",&x,&y);
            Query_chain(x,y);
            printf("%d\n",ans%Mod);
        }
        if(opt==3)
        {
            scanf("%d%d",&x,&z);
            Update_tree(x,z);
        }
        if(opt==4)
        {
            scanf("%d",&x);
            Query_tree(x);
            printf("%d\n",ans%Mod);
        }
    }
    return 0;
}

码量不过200行+

 

posted @ 2019-08-06 19:33  Thm-V  阅读(210)  评论(0编辑  收藏  举报