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

P1501 [国家集训队]Tree II

时间:2019-01-27 00:22:21      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:space   let   namespace   pac   const   lld   http   stream   inline   

做法

P1501 [国家集训队]Tree II

树上懒惰标记维护动态路径模板题

做法

其实做这题也能练一下对\(LCT\)的了解

我们对\(x,y\)这条路径修改时:\(Split(x,y);....(y)\),传到\(y\)上去就行了

我们发现不管什么操作都会用到\(Access\),其中把底下的点上旋\(splay\)的同时会把\(y\)上的标记取下来

和线段树差不多吧不知道为什么是道黑题

My complete code

写代码(15min)+调试(15min)感觉比模板还容易打

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e6,p=51061;
inline LL Read(){
    LL x(0),f(1);char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
LL n,m;
LL val[maxn],sum[maxn],lazya[maxn],lazym[maxn],fa[maxn],son[maxn][2],r[maxn],size[maxn],sta[maxn];

inline bool Notroot(LL x){
    return (son[fa[x]][0]==x||son[fa[x]][1]==x);
}
inline void Pushr(LL x){
    swap(son[x][0],son[x][1]); r[x]^=1;
}
inline void Update(LL x){
    LL lc(son[x][0]),rc(son[x][1]);
    sum[x]=(sum[lc]+sum[rc]+val[x])%p,size[x]=size[lc]+size[rc]+1;
}
inline void Pusha(LL x,LL w){
    sum[x]=(sum[x]+size[x]*w%p)%p,val[x]=(val[x]+w)%p,lazya[x]=(lazya[x]+w)%p;
}
inline void Pushm(LL x,LL w){
    sum[x]=sum[x]*w%p,val[x]=val[x]*w%p,lazym[x]=lazym[x]*w%p,lazya[x]=lazya[x]*w%p;
}
inline void Pushdown(LL x){
    LL lc(son[x][0]),rc(son[x][1]);
    if(lazym[x]!=1){
        if(lc) Pushm(lc,lazym[x]);
        if(rc) Pushm(rc,lazym[x]);
        lazym[x]=1;
    }
    if(lazya[x]){
        if(lc) Pusha(lc,lazya[x]);
        if(rc) Pusha(rc,lazya[x]);
        lazya[x]=0;
    }
    if(r[x]){
        if(lc) Pushr(lc);
        if(rc) Pushr(rc);
        r[x]=0;
    }
}
inline void Rotate(LL x){
    LL y(fa[x]),z(fa[y]),lz(son[y][1]==x);
    if(Notroot(y)) son[z][son[z][1]==y]=x; fa[x]=z;
    son[y][lz]=son[x][lz^1];
    if(son[y][lz]) fa[son[y][lz]]=y;
    son[x][lz^1]=y; fa[y]=x;
    Update(y),Update(x);
}
inline void Splay(LL x){
    LL y(x),top(0);
    sta[++top]=y;
    while(Notroot(y)) sta[++top]=y=fa[y];
    while(top) Pushdown(sta[top--]);
    while(Notroot(x)){
        y=fa[x];
        if(Notroot(y)){
            LL z(fa[y]);
            if(((son[y][1]==x)^(son[z][1]==y))==0) Rotate(y);
            else Rotate(x);
        }Rotate(x);
    }
}
inline void Access(LL x){
    for(LL y=0;x;y=x,x=fa[x]){
        Splay(x),son[x][1]=y; Update(x);
    }
}
inline void Makeroot(LL x){
    Access(x),Splay(x),Pushr(x);
}
inline void Split(LL x,LL y){
    Makeroot(x),Access(y),Splay(y);
}
inline void Link(LL x,LL y){
    Makeroot(x),fa[x]=y;
}
inline void Delet(LL x,LL y){
    Split(x,y);
    fa[x]=son[y][0]=0;
    Update(y);
}
int main(){
    n=Read(),m=Read();
    for(LL i=1;i<=n;++i) val[i]=lazym[i]=size[i]=1;
    for(LL i=1;i<n;++i){
        LL u(Read()),v(Read());
        Link(u,v);
    }
    while(m--){
        char ch; scanf(" %c",&ch);
        if(ch=='+'){
            LL x(Read()),y(Read()),w(Read());
            Split(x,y); Pusha(y,w);
        }else if(ch=='-'){
            LL x1(Read()),y1(Read()),x2(Read()),y2(Read());
            Delet(x1,y1),Link(x2,y2);
        }else if(ch=='*'){
            LL x(Read()),y(Read()),w(Read());
            Split(x,y); Pushm(y,w);
        }else{
            LL x(Read()),y(Read());
            Split(x,y);
            printf("%lld\n",sum[y]);
        }
    }
    return 0;
}

P1501 [国家集训队]Tree II

标签:space   let   namespace   pac   const   lld   http   stream   inline   

原文地址:https://www.cnblogs.com/y2823774827y/p/10325330.html

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