码迷,mamicode.com
首页 > 其他好文 > 详细

树剖模板

时间:2017-11-14 22:30:27      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:sum   iostream   swap   code   uil   include   img   real   namespace   

技术分享
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define l(x) (x<<1)
#define r(x) ((x<<1)|1)
using namespace std;
struct EDG
{
    int to,nex;
}es[1000010];
int n,m,r,p;
int first[100010];
int cnt; 
void link(int a,int b)
{
    es[++cnt].nex=first[a];
    first[a]=cnt;
    es[cnt].to=b;
}
LL a[1000100];
//树剖↓
LL real[1000010],sid[1000010],hson[1000010],fa[1000010],dep[1000010],size[1000010],top[1000010];
LL tot;
void dfs1(int x)
{
    size[x]=1;
    for(int i=first[x];i;i=es[i].nex)
    {
        int v=es[i].to;
        if(v!=fa[x])
        {
            fa[v]=x;
            dep[v]=dep[x]+1;
            dfs1(v);
            if(hson[x]==0||size[hson[x]]<size[v])
            {
                hson[x]=v;
            }
            size[x]+=size[v];
        }
    }
}
void dfs2(int x,int anc)
{
    top[x]=anc;
    sid[x]=++tot;
    real[tot]=x;
    if(hson[x]==0) return;
    dfs2(hson[x],anc);
    for(int i=first[x];i;i=es[i].nex)
    {
        int v=es[i].to;
        if(v!=hson[x]&&v!=fa[x])
        {
            dfs2(v,v);
        }
    }
}
//树剖↑ 
//线段树 ↓ 
struct Tre
{
    LL sum,tag;
}Tr[1000100];
void update(LL id)
{
    Tr[id].sum=Tr[l(id)].sum+Tr[r(id)].sum;
}
void pushdown(LL l,LL r,LL id)
{
    Tr[r(id)].tag+=Tr[id].tag;
    Tr[l(id)].tag+=Tr[id].tag;
    Tr[id].sum+=(r-l+1)*Tr[id].tag;
    Tr[id].tag=0;
}
void build(LL l,LL r,LL id)
{
    if(l==r)
    {
        Tr[id].sum=a[real[l]];
        return;
    }
    LL mid=(l+r)/2;
    build(mid+1,r,r(id));
    build(l,mid,l(id));
    update(id);
}
void add(LL al,LL ar,LL x,LL l,LL r,LL id)
{
    if(l>ar||r<al) return;
    if(al==l&&ar==r) {Tr[id].tag+=x;return;}
    pushdown(l,r,id);
    LL mid=(r+l)/2;
    if(mid>=al) add(al,min(mid,ar),x,l,mid,l(id));
    if(mid<ar) add(max(mid+1,al),ar,x,mid+1,r,r(id));
    pushdown(l,mid,l(id));
    pushdown(mid+1,r,r(id));
    update(id);
}
LL query(LL al,LL ar,LL l,LL r,LL id)
{
    if(l>r) return 0LL;
    if(al==l&&ar==r) {return Tr[id].tag*(r-l+1)+Tr[id].sum;}
    pushdown(l,r,id);
    LL mid=(r+l)/2;
    LL t=0;
    if(mid>=al) t+=query(al,min(mid,ar),l,mid,l(id));
    if(mid<ar) t+=query(max(mid+1,al),ar,mid+1,r,r(id));
    return t;
}
//线段树 ↑ 
//树剖用线段树维护↓
void tr_add(LL x,LL v)//x点及其子孙权值加v 
{
    add(sid[x],sid[x]+size[x]-1,v,1,n,1);
}
LL tr_query(LL x)//x点及其子孙权值和 
{
    return query(sid[x],sid[x]+size[x]-1,1,n,1)%p;
}
LL chain_add(LL x,LL y,LL v)//x到y的链上每个点加v 
{
    LL tx,ty;
    tx=top[x];ty=top[y];
    while(tx!=ty)
    {
        if(dep[tx]<dep[ty])
        {
            swap(x,y);
            swap(tx,ty);    
        }
        add(sid[tx],sid[x],v,1,n,1);
        x=fa[tx];tx=top[x];    
    }
    if(dep[x]<dep[y]) swap(x,y);
    add(sid[y],sid[x],v,1,n,1);    
} 
LL chain_query(LL x,LL y)//查询x到y的链上权值和 
{
    LL tx,ty,t=0;
    tx=top[x];ty=top[y];
    while(tx!=ty)
    {
        if(dep[tx]<dep[ty]) {swap(tx,ty);swap(x,y);}
        (t+=query(sid[tx],sid[x],1,n,1))%=p;
        x=fa[tx];tx=top[x];
    }
    if(dep[x]<dep[y]) swap(x,y);
    (t+=query(sid[y],sid[x],1,n,1))%=p;
    return t;
}
//树剖用线段树维护↑ 
int main()
{
    scanf("%d%d%d%d",&n,&m,&r,&p);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        link(x,y);link(y,x);
    }
    dep[r]=1;
    dfs1(r);
    dfs2(r,r);
    build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        int q;
        scanf("%d",&q);
        if(q==1)
        {
            LL x,y,z;
            scanf("%lld%lld%lld",&x,&y,&z);
            chain_add(x,y,z);
        }
        if(q==2)
        {
            LL x,y;
            scanf("%lld%lld",&x,&y);
            cout<<chain_query(x,y);
            cout<<endl;
        }
        if(q==3)
        {
            LL x,z;
            scanf("%lld%lld",&x,&z);
            tr_add(x,z);
        }
        if(q==4)
        {
            LL x;
            scanf("%lld",&x);
            cout<<tr_query(x);
            cout<<endl;
        }
    }
}
树链剖分模板

 

树剖模板

标签:sum   iostream   swap   code   uil   include   img   real   namespace   

原文地址:http://www.cnblogs.com/wjxgy/p/7834767.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!