首页 > 其他 > 详细

树剖小结(简述)

时间:2020-02-05 20:14:41      阅读:58      评论:0      收藏:0      [点我收藏+]

比较恶心,特别是线段树
题目链接:P3384 【模板】重链剖分
详解见:大佬博客
我的代码:

\(Code\):

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=100005;
int mod,n,m,root;
int f[MAXN],dep[MAXN],son[MAXN],tot[MAXN];
int t[MAXN],b[MAXN],id[MAXN],c=0,top[MAXN];
struct edge
{
    int to,nxt;
}e[MAXN<<1];
int head[MAXN],cnt=0;
void swap(int *a,int *b){int t=*a;*a=*b,*b=t;}
void add(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
int dfs1(int cur,int fa,int deep)
{
    dep[cur]=deep;
    f[cur]=fa;
    int maxn=-1;
    tot[cur]=1;
    for(int i=head[cur];i;i=e[i].nxt)
    {
        int j=e[i].to;
        if(!(j^fa)) continue;
        tot[cur]+=dfs1(j,cur,deep+1);
        if(tot[j]>maxn) maxn=tot[j],son[cur]=j;
    }
    return tot[cur];
}
void dfs2(int cur,int topf)
{
    id[cur]=++c;
    t[c]=b[cur];
    top[cur]=topf;
    if(!son[cur]) return;
    dfs2(son[cur],topf);
    for(int i=head[cur];i;i=e[i].nxt)
    {
        int j=e[i].to;
        if(!id[j]) dfs2(j,j);
    }
}
struct node
{
    int l,r,sum,lazy;
    node()
    {
        l=r=sum=lazy=0;
    }
}a[MAXN<<2];
void update(int k){a[k].sum=(a[k<<1].sum+a[k<<1|1].sum)%mod;}
void build(int k,int l,int r)
{
    int mid=(l+r)>>1;
    a[k].l=l,a[k].r=r;
    if(l==r)
    {
        a[k].sum=t[l];
        return;
    }
    build(k<<1,l,mid),build(k<<1|1,mid+1,r);
    update(k);
}
void lazydown(int k)
{
    if(a[k].l==a[k].r)
    {
        a[k].lazy=0;
        return;
    }
    a[k<<1].sum=(a[k<<1].sum+(a[k<<1].r-a[k<<1].l+1)*a[k].lazy%mod)%mod;
    a[k<<1|1].sum=(a[k<<1|1].sum+(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lazy%mod)%mod;
    a[k<<1].lazy=(a[k<<1].lazy+a[k].lazy)%mod;
    a[k<<1|1].lazy=(a[k<<1|1].lazy+a[k].lazy)%mod;
    a[k].lazy=0;
}
void change(int k,int l,int r,int x)
{
    int mid=(a[k].l+a[k].r)>>1;
    if(a[k].l==l&&a[k].r==r)
    {
        a[k].sum=(a[k].sum+(a[k].r-a[k].l+1)*x%mod)%mod;
        a[k].lazy=(a[k].lazy+x)%mod;
        return;
    }
    if(a[k].lazy) lazydown(k);
    if(r<=mid) change(k<<1,l,r,x);
    else if(l>mid) change(k<<1|1,l,r,x);
    else change(k<<1,l,mid,x),change(k<<1|1,mid+1,r,x);
    update(k);
}
int query(int k,int l,int r)
{
    int mid;
    if(a[k].lazy) lazydown(k);
    if(a[k].l==l&&a[k].r==r) return a[k].sum%mod;
    mid=(a[k].l+a[k].r)>>1;
    if(r<=mid) return query(k<<1,l,r)%mod;
    if(l>=mid+1) return query(k<<1|1,l,r)%mod;
    return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%mod;
}
void tree_add(int l,int r,int x)
{
    while(top[l]!=top[r])
    {
        if(dep[top[l]]<dep[top[r]]) swap(l,r);
        change(1,id[top[l]],id[l],x);
        l=f[top[l]];
    }
    if(dep[l]>dep[r]) swap(l,r);
    change(1,id[l],id[r],x);
    return;
}

int tree_query(int l,int r)
{
    int ans=0;
    while(top[l]!=top[r])
    {
        if(dep[top[l]]<dep[top[r]]) swap(l,r);
        ans=(ans+query(1,id[top[l]],id[l]))%mod;
        l=f[top[l]];
    }
    if(dep[l]>dep[r]) swap(l,r);
    ans=(ans+query(1,id[l],id[r]))%mod;
    return ans%mod;
}
void son_add(int k,int x){change(1,id[k],id[k]+tot[k]-1,x);}
int son_query(int k){return query(1,id[k],id[k]+tot[k]-1);} 
int u,v,flag,x,y,z;
int main()
{
    scanf("%d%d%d%d",&n,&m,&root,&mod);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(root,root,1);
    dfs2(root,root);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&flag,&x);
        if(flag==1)
        {
            scanf("%d%d",&y,&z);
            tree_add(x,y,z);
        }
        else if(flag==2)
        {
            scanf("%d",&y);
            printf("%d\n",tree_query(x,y)%mod);
        }
        else if(flag==3)
        {
            scanf("%d",&y);
            son_add(x,y);
        }
        else printf("%d\n",son_query(x)%mod);
    }
    return 0;
}

因为写炸线段树,因为左右端点反了只有\(30pts\)(数据水?)
还看了\(bi\)站视频,
主要思想是根据\(dfs\)序使链和子树映射在线段树上,使得计算的相关点重新编号后在一个区间中,可证明时间复杂度为\(O(mlog^2n)\)似乎懂了
就这样

树剖小结(简述)

原文:https://www.cnblogs.com/tlx-blog/p/12264844.html

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