【P3384】【模板】树链剖分

来源:互联网 发布:布拉德利比尔数据 编辑:程序博客网 时间:2024/06/05 21:57

树链剖分就是将树上的点通过轻重链剖分来将其合理地(即时间复杂度令人满意)hash成一个线段,之后再用线段树来维护。
也可以想象成将树上最长的链拿出来,短的链就在旁边填填补补这种感觉?
详细讲的话,像我这种蒟蒻肯定是讲不好的,各种分析也不会,丢个代码直接细软跑好了。
hashh是正向hash。
hashv是反向hash,致敬韦神。

#include<bits/stdc++.h>#define fer(i,j,n) for(int i=j;i<=n;i++)#define far(i,j,n) for(int i=j;i>=n;i--)#define ll long long#define pa pair<int,int>const int maxn=500010;const int INF=1e9+7;using namespace std;/*----------------------------------------------------------------------------*/inline ll read(){    char ls;ll x=0,sng=1;    for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;    for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';    return x*sng;}/*----------------------------------------------------------------------------*/ll n,m,root,mod; struct kaga{    int next;    int point;}e[maxn];struct akagi{    int l,r;    ll sum,lazy;}tr[maxn];int last[maxn],k=0,fa[maxn],size[maxn],son[maxn],belong[maxn],hashh[maxn],hashv[maxn],dep[maxn],v[maxn];void sumup(int x){    tr[x].sum=(tr[x<<1].sum+tr[x<<1|1].sum)%mod;    return ;}void pushdown(int x){    int y=tr[x].lazy;    if(y)    {        tr[x<<1].lazy+=y;        tr[x<<1].sum+=(tr[x<<1].r-tr[x<<1].l+1)*y;        tr[x<<1|1].lazy+=y;        tr[x<<1|1].sum+=(tr[x<<1|1].r-tr[x<<1|1].l+1)*y;        tr[x].lazy=0;    }    return ;}void build(int x,int l,int r){    int mid=(l+r)>>1;    tr[x].l=l;tr[x].r=r;    if(l==r)    {        tr[x].sum=v[hashv[l]];        tr[x].lazy=0;        return ;    }    build(x<<1,l,mid);    build(x<<1|1,mid+1,r);    sumup(x);    return ;}void change(int x,int L,int R,int val){    int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;    if(L<=l&&r<=R)    {        tr[x].lazy+=val;tr[x].lazy%=mod;        tr[x].sum+=val*(r-l+1);tr[x].sum%=mod;        return ;    }    pushdown(x);    if(R<=mid)change(x<<1,L,R,val);    else if(L>mid)change(x<<1|1,L,R,val);    else change(x<<1,L,mid,val),change(x<<1|1,mid+1,R,val);    sumup(x);    return ;}ll query(int x,int L,int R){    int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;    if(L<=l&&r<=R)return tr[x].sum;    pushdown(x);    if(R<=mid)query(x<<1,L,R);    else if(L>mid)query(x<<1|1,L,R);    else return (query(x<<1,L,mid)+query(x<<1|1,mid+1,R))%mod;}void add_edge(int x,int y){    e[++k].next=y;e[k].point=last[x];last[x]=k;}void insert(int x,int y){    add_edge(x,y);    add_edge(y,x);}void dfs1(int x,int fat){    fa[x]=fat;    dep[x]=dep[fat]+1;    size[x]=1;    for(int j=last[x];j;j=e[j].point)    {        int y=e[j].next;        if(y==fat)continue;        dfs1(y,x);        size[x]+=size[y];        if(!son[x]||size[y]>size[son[x]])        son[x]=y;       }}void dfs2(int x,int top){    belong[x]=top;    hashh[x]=++k;    hashv[k]=x;    if(!son[x])return ;    dfs2(son[x],top);    for(int j=last[x];j;j=e[j].point)    {        int y=e[j].next;        if(y!=son[x]&&y!=fa[x])        dfs2(y,y);      }}void update(int x,int y,int val){    int topx=belong[x];    int topy=belong[y];    while(topx!=topy)    {        if(dep[topx]<dep[topy])        {            swap(x,y);            swap(topx,topy);            }        change(1,hashh[topx],hashh[x],val);        x=fa[topx];        topx=belong[x];    }    if(dep[x]>dep[y])swap(x,y);    change(1,hashh[x],hashh[y],val);}ll sigma(int x,int y){    ll sum=0;    int topx=belong[x];    int topy=belong[y];    while(topx!=topy)    {        if(dep[topx]<dep[topy])        {            swap(x,y);            swap(topx,topy);            }        sum+=query(1,hashh[topx],hashh[x]);        sum%=mod;        x=fa[topx];        topx=belong[x];    }    if(dep[x]>dep[y])swap(x,y);    sum+=query(1,hashh[x],hashh[y]);    return sum%mod;}void updateson(int x,int val){    int left=hashh[x];    int right=hashh[x]+size[x]-1;    change(1,left,right,val);}ll sigmason(int x){    int left=hashh[x];    int right=hashh[x]+size[x]-1;    return query(1,left,right)%mod;}int main(){    n=read();m=read();root=read();mod=read();    fer(i,1,n)v[i]=read();    fer(i,1,n-1)    {        int x=read(),y=read();        insert(x,y);    }    k=0;    dfs1(root,0);    dfs2(root,root);    build(1,1,n);    fer(i,1,m)    {        int opt=read();        if(opt==1)        {            int x=read(),y=read(),z=read();            update(x,y,z);          }        else if(opt==2)        {            int x=read(),y=read();            cout<<sigma(x,y)<<endl;         }        else if(opt==3)        {            int x=read(),y=read();            updateson(x,y);         }        else        {            int x=read();            cout<<sigmason(x)<<endl;            }    }} 
原创粉丝点击