首页 > 其他分享 >树链剖分 学习心得

树链剖分 学习心得

时间:2023-10-13 14:36:12浏览次数:31  
标签:node return 剖分 int void 学习心得 树链 add sum

Bug 都写在代码开头了,就不复述了。

还有一个智障的错误是注释调试代码的时候把同一行的正式代码也给注释掉了(

写得非常精彩。

/*  
  bug:1.rev、id要分清!  
      2.mod()函数的情况不能写一半就跑路!  
      3.别忘了先给tree build()一下!  
      4.出界条件认真想一遍再写!  
      5.还有出界的!  
      6.LazyTag pushdown()之后还需要重置!  
  Question:  
      1.有多少对长度为n 的rev 和id 是相同的?  
 */  
#include<bits/stdc++.h>  
using namespace std;  
#define N 100005  
#define M 200005  
#define ll long long  
//#define DEBUG  
#ifdef DEBUG  
#define debugtive(x) int x  
#define debug(x) {printf("%5s=",#x);cout<<(x)<<"\n";}  
#define debugs(x,l,r){printf("%5s:",#x);for(int i=l;i<=r;++i){cout<<x[i]<<" ";}putchar('\n');}  
#else  
#define debugtive(x)  
#define debug(x)  
#define debugs(x,l,r)  
#endif  
ll n,m,R,P,val[N],ans;  
int tot,first[N],nxt[M],to[M];  
int top[N],rev[N],id[N],fah[N],siz[N],son[N],dfn,dep[N];  
void add(int x,int y){  
    nxt[++tot]=first[x];  
    to[tot]=y;  
    first[x]=tot;  
    return;  
}  
void Add(ll &x,ll y){  
    x+=y;  
    if(x>=P)x-=P;  
}  
ll mod(ll x){  
    if(x>=P)return x-P;  
    return x;                                //bug #2  
}  
struct{  
    struct node{  
        int L,R;  
        node *l,*r;  
        ll sum,add;  
        debugtive(lev);  
        node(node *a=NULL,node *b=NULL,ll c=0,ll d=0){  
            l=a,r=b,sum=c,add=d;  
        }  
        void bu(){  
            if(l==NULL)l=new node();  
            if(r==NULL)r=new node();  
        }  
        void pushup(){  
            l->pushdown();  
            r->pushdown();  
            sum=mod(l->sum+r->sum);  
        }  
        void pushdown(){  
            if(add){  
                sum=(sum+(R-L+1)*add)%P;  
                if(l!=NULL)Add(l->add,add);    //bug #5 l、r可能出界所以要判断  
                if(r!=NULL)Add(r->add,add);    //bug #5 ↑  
                add=0;                        //bug #6 别忘了重置lazytag!  
            }  
            return;  
        }  
#ifdef DEBUG  
        void out(bool andson){  
            for(int i=1;i<=lev;++i)putchar('\t');  
            printf("{[%d,%d]:sum=%lld add=%lld}\n",L,R,sum,add);  
            if(andson){  
                if(l!=NULL)l->out(1);  
                if(r!=NULL)r->out(1);  
            }  
        }  
#endif  
    };  
    node* root;  
    void init(){  
        this->root=new node();  
        root->bu();  
    }  
    void build(node*x,int l,int r){  
        x->L=l,x->R=r;  
        if(l==r){  
            x->sum=val[id[l]];                //bug #1  
            return;  
        }  
        x->bu();  
#ifdef DEBUG  
        x->l->lev=x->r->lev=x->lev+1;  
#endif  
        int mid=(l+r)>>1;  
        build(x->l,l,mid);  
        build(x->r,mid+1,r);  
        x->pushup();  
        return;  
    }  
    ll query(node*x,int l,int r){  
        if(x->L>r||x->R<l)return 0;            //bug #4  
        x->pushdown();  
        if(x->L>=l&&x->R<=r)return x->sum;  
        return mod(query(x->l,l,r)+query(x->r,l,r));  
    }  
    void update(node*x,int l,int r,ll val){  
        if(x->L>r||x->R<l)return;            //bug #4  
        if(x->L>=l&&x->R<=r){  
//            printf("plate\n");  
            Add(x->add,val);  
            x->pushdown();  
            return;  
        }  
        x->pushdown();                        //这里必须有,因为统计父节点sum的时候不会计算add,所以要把add给pushdown掉。  
    //        printf("update[%d,%d]\n",l,r);x->out(1);  
        update(x->l,l,r,val);  
        update(x->r,l,r,val);  
        x->pushup();  
        return;  
    }  
}tree;  
void dfs1(int x){  
    siz[x]=1;  
    for(int e=first[x];e;e=nxt[e]){  
        int u=to[e];  
        if(siz[u])continue;  
        fah[u]=x;  
        dep[u]=dep[x]+1;  
        dfs1(u);  
        siz[x]+=siz[u];  
        if(siz[u]>siz[son[x]])son[x]=u;  
    }  
}  
void dfs2(int x,int curtop){  
    top[x]=curtop;  
    rev[x]=++dfn;  
    id[dfn]=x;  
    if(son[x])dfs2(son[x],curtop);  
    for(int e=first[x];e;e=nxt[e]){  
        int u=to[e];  
        if(top[u])continue;  
        if(u!=son[x]){  
            dfs2(u,u);  
        }  
    }  
    return;  
}  
int main(){  
    int x,y,z,opr;  
    scanf("%lld %lld %lld %lld",&n,&m,&R,&P);  
    for(int i=1;i<=n;++i){  
        scanf("%lld",&val[i]);  
    }  
    for(int i=1;i<n;++i){  
        scanf("%d %d",&x,&y);  
        add(x,y);  
        add(y,x);  
    }  
    top[R]=R;dep[R]=1;  
    dfs1(R);  
    dfs2(R,R);  
    tree.init();  
#ifdef DEBUG  
    tree.root->lev=1;  
    debug(tree.root->lev);  
#endif  
    tree.build(tree.root,1,n);                //bug #3  
//    debugs(rev,1,n);  
//    debugs( id,1,n);  
//    debugs(top,1,n);  
//    debugs(dep,1,n);  
//    debugs(siz,1,n);  
//    debugs(val,1,n);  
//    tree.root->out(1);  
    for(int i=1;i<=m;++i){  
        scanf("%d",&opr);  
        switch(opr){  
        case 1:  
            scanf("%d %d %d",&x,&y,&z);  
            while(top[x]!=top[y]){  
                if(dep[top[x]]<dep[top[y]])swap(x,y);  
                tree.update(tree.root,rev[top[x]],rev[x],z);  
                x=fah[top[x]];  
            }  
            if(rev[x]<rev[y])swap(x,y);  
            tree.update(tree.root,rev[y],rev[x],z);  
//            tree.root->out(1);  
            break;  
        case 2:  
            scanf("%d %d",&x,&y);  
            ans=0;  
            while(top[x]!=top[y]){  
                if(dep[top[x]]<dep[top[y]])swap(x,y);  
                Add(ans,tree.query(tree.root,rev[top[x]],rev[x]));  
                x=fah[top[x]];  
            }  
            if(rev[x]<rev[y])swap(x,y);  
            Add(ans,tree.query(tree.root,rev[y],rev[x]));  
            printf("%lld\n",ans%P);  
            break;  
        case 3:  
            scanf("%d %d",&x,&z);  
            debug(rev[x]);  
            debug(rev[x]+siz[x]-1);  
            tree.update(tree.root,rev[x],rev[x]+siz[x]-1,z);  
//            tree.root->out(1);  
            break;  
        default:  
            scanf("%d",&x);  
            printf("%lld\n",tree.query(tree.root,rev[x],rev[x]+siz[x]-1)%P);  
            break;  
        }  
    }  
    return 0;  
}  
//[Error]ld returned 1 exited status.

标签:node,return,剖分,int,void,学习心得,树链,add,sum
From: https://www.cnblogs.com/DZhearMins/p/17762013.html

相关文章

  • 数位 dp 学习心得
    感觉非常牛逼。最牛逼的是很多情况下要去掉前导零。去掉前导零的方法通常是先忽略前导零的约束,最后再容斥掉有多少0。LuoguP2602数字计数来自【详细解释】数字计数ZJOJp2602一道练习数位DP的好题-moye到碗里来的博客-洛谷博客(luogu.com.cn)那么我们首先看题,对于这......
  • 割边+割点 学习心得
    先背诵tarjan板子#include<bits/stdc++.h>using namespace std;#define N 10005#define M 100005int tot,first[N],nxt[M],to[M];void add(int x,int y){    nxt[++tot]=first[x];    first[x]=tot;    to[tot]=y;}int n......
  • 重链剖分
    代码思路主体部分:初始化,剖分链,求LCA(也就是dfs1,dfs2,LCA三个函数)辅助部分:structPoint{//节点信息多的时候会习惯开个结构体来存 intdep,siz,son,top,fath; //点的深度子树大小重儿子所在重链的链头父亲节点 //没有重儿子则son=0 intid,l,r;//求lca不......
  • 树链剖分【产品说明书】
    一种暴论:树链剖分=多叉树上分块+线段树适用范围总之就是数据结构的基础问题。总的来说,树链剖分可以在\(O(m\logn)\)的时间复杂度中,解决大多数树上路径问题,包括其修改、维护和查询。例如这样的一道模板题又例如……(请直接跳到本文最后一章)产品简介树链剖分有两种:重......
  • 树链剖分
    树链剖分树链剖分常用于解决树上路径查询的问题。原理:对于树上两点之间的路径\(u\)->\(v\),根据某种策略,将之拆分成若干条链,然后利用线段树等数据结构单独维护这些子链,最后将答案合并。常用的剖分方法:轻重边划分。剖分树种的边可以分为两种边:重边和轻边。设\(size_u\)......
  • 算法:树链剖分
    去年就看过树链剖分的视频了,当时连树状数组,线段树都没学,对树的dfs也一知半解,所以基本完全听不懂。昨天又重新看了一般,感觉思路挺简单,应该比线段树简单吧,从用树链剖分求LCA来看确实是这样的,但是没有想到的是用线段树维护树链剖分。QAQ这应该是我打过最长的代码吧!(3K)树链剖分......
  • 二分图匹配 - 学习心得
    就是跑匈牙利算法就行了,难点完全在于建图。模板水题Link#include<bits/stdc++.h>constintN=510;intn,m,e;intG[N][N],match[N];std::bitset<N>vis;namespaceBlackWhiteGraph{ inlinevoidInit(void){ scanf("%d%d",&n,&m); inta,t; for(regis......
  • 浅谈树链剖分—轻重链剖分
    闲话似乎会有很多种树剖,什么长链剖分之类的,但是暂时只会轻重链剖分(可怜)。以前的版本在这里,但是感觉写的太粗糙了,所以决定重写一篇(我也不知道为什么要一直写树剖而不写点别的)。正文引入如果给出一个序列,有一些区间修改查询之类的操作,直接上线段树什么的就完事了,但是如果给出的......
  • 树链剖分
    前言:本人太弱了,看着题解调了一下午,才A了树剖的板子题,所以写篇博客纪念一下(其实是怕自己忘了树剖怎么做)。本文以板子题为例子定义:树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个于且只属于一条链,然后再通过数据结构(树状数组、BST、SPL......
  • [学习笔记] 树链剖分
    叫复习笔记或许更好。树链剖分就是把树剖成链去解决一些问题。定义重子节点:子节点中子树大小最大的节点。轻子节点:除重子节点外的其他子节点。重边:到重子节点的边。轻边:到轻子节点的边。记号\(dfn[x]\):DFS序,也是在线段树中的编号。\(son[x]\):重子节点。\(dep[x]\)......