Miserable Faith

给定一棵树,每次可以将一条链到根染成一种新的颜色,对于一条边,它的权值在相邻两个点颜色不同时为1,否则为0。

查询一条路径的边权和,子树里所有点到当前点的距离和,所有路径边权和为0的点对。

链上染色这个操作,很容易就可以想到用\(LCT\)来维护,这个就是\(LCT\)\(access\)​操作,在进行轻重边转换的时候,相当于我们需要做一个子树加减的操作,这个东西可以用\(dfs\)序类维护。

注意在\(LCT\)加子树的时候要先\(findroot\)找到真正的根,再去加。

#include<bits/stdc++.h>
#define N 100009
using namespace std;
typedef long long ll;
int tot,head[N];
int n,q;
ll tr[N<<2],la[N<<2],size[N];
int dfn[N],p[N][21],deep[N];
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
struct edge{
    int n,to;
}e[N<<1];
inline void add(int u,int v){
    e[++tot].n=head[u];
    e[tot].to=v;
    head[u]=tot;
}
inline void pushdown(int cnt,int l,int r){
    int mid=(l+r)>>1;
    tr[cnt<<1]+=(mid-l+1)*la[cnt];
    tr[cnt<<1|1]+=(r-mid)*la[cnt];
    la[cnt<<1]+=la[cnt];
    la[cnt<<1|1]+=la[cnt];
    la[cnt]=0; 
}
void upd(int cnt,int l,int r,int L,int R,int x){
    if(l>=L&&r<=R){
        tr[cnt]+=x*(r-l+1);
        la[cnt]+=x;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(cnt,l,r);
    if(mid>=L)upd(cnt<<1,l,mid,L,R,x);
    if(mid<R)upd(cnt<<1|1,mid+1,r,L,R,x);
    tr[cnt]=tr[cnt<<1]+tr[cnt<<1|1];
}
ll query(int cnt,int l,int r,int L,int R){
    if(l>=L&&r<=R)return tr[cnt];
    pushdown(cnt,l,r);
    int mid=(l+r)>>1;ll ans=0;
    if(mid>=L)ans+=query(cnt<<1,l,mid,L,R);
    if(mid<R)ans+=query(cnt<<1|1,mid+1,r,L,R);
    return ans; 
}
void clear(int cnt,int l,int r){
    tr[cnt]=la[cnt]=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    clear(cnt<<1,l,mid);
    clear(cnt<<1|1,mid+1,r);
}
struct LCT{
    #define ls c[x][0]
    #define rs c[x][1]
    int top,c[N][2],fa[N],val[N],rev[N],q[N];
    ll dp[N];
    void clear(){
        for(int i=1;i<=n;++i){
            dp[i]=val[i]=rev[i]=fa[i]=c[i][0]=c[i][1]=0;
        }
    }
    inline void pushup(int x){
        dp[x]=dp[c[x][0]]+dp[c[x][1]]+1;
    }
    inline void pushdown(int x){
        if(rev[x]){
              rev[ls]^=1;rev[rs]^=1;rev[x]^=1;
              swap(ls,rs);
        }
    }
    inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
    inline bool ge(int x){return c[fa[x]][1]==x;}
    inline void rotate(int x){
        int y=fa[x],z=fa[y],o=ge(x);
        if(!isroot(y))c[z][ge(y)]=x;
        fa[x]=z;fa[y]=x;fa[c[x][o^1]]=y;
        c[y][o]=c[x][o^1];c[x][o^1]=y;
        pushup(y);pushup(x);
    }
    inline void splay(int x){
        top=1;q[top]=x;
        for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
        for(int i=top;i;--i)pushdown(q[i]);
        while(!isroot(x)){
            int y=fa[x],z=fa[y];
            if(!isroot(y))
                if(ge(x)==ge(y))rotate(y);
                else rotate(x);
            rotate(x);
        }
    }
    inline void access(int x){
        for(int y=0;x;y=x,x=fa[x]){
            splay(x);
            int now=c[x][1];
            if(now){  
               now=find(now);
               upd(1,1,n,dfn[now],dfn[now]+size[now]-1,1);
            } 
            c[x][1]=y;pushup(x);
            if(y){
               y=find(y);
               upd(1,1,n,dfn[y],dfn[y]+size[y]-1,-1);
            }
            
        }
    } 
    inline void makeroot(int x){
        access(x);splay(x);rev[x]^=1;
    }
    inline int find(int x){
        while(c[x][0])pushdown(x),x=c[x][0];
        return x;
    }
    inline void split(int x,int y){
        makeroot(x);access(y);splay(y);
    }
    inline void link(int x,int y){
        makeroot(x);fa[x]=y;
    }
    inline void cut(int x,int y){
        split(x,y);
        if(c[y][0]==x&&fa[x]==y&&!c[x][1])c[y][0]=0,fa[x]=0;
        pushup(y);
    }
}lc;
inline int getlca(int u,int v){
    if(deep[u]<deep[v])swap(u,v);
    for(int i=20;i>=0;--i)if(deep[u]-(1<<i)>=deep[v]){
        u=p[u][i];
    }
    if(u==v)return u;
    for(int i=20;i>=0;--i)if(p[u][i]!=p[v][i]){
        u=p[u][i];
        v=p[v][i];
    }
    return p[u][0];
}
void dfs(int u,int fa){
    dfn[u]=++dfn[0];
    upd(1,1,n,dfn[u],dfn[u],deep[u]);
    size[u]=1;
    for(int i=1;i<=20;++i)p[u][i]=p[p[u][i-1]][i-1];
    for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
        int v=e[i].to;
        deep[v]=deep[u]+1;p[v][0]=u;
        lc.fa[v]=u;
        dfs(v,u);
        size[u]+=size[v];
    }
}
int main(){
    int T;
    scanf("%d",&T); 
    while(T--){
        scanf("%d%d",&n,&q);
        int x,y;
        for(int i=1;i<n;++i){
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x); 
        }
        dfs(1,0);
        int u,v,opt; 
        for(int i=1;i<=q;++i){
            scanf("%d",&opt);
            if(opt==1){
                scanf("%d%d",&u,&v);
                lc.split(u,v);
            }
            if(opt==2){
                scanf("%d%d",&u,&v);
                int lca=getlca(u,v);
                int x=query(1,1,n,dfn[u],dfn[u])+query(1,1,n,dfn[v],dfn[v])-2*query(1,1,n,dfn[lca],dfn[lca]);
                cout<<query(1,1,n,dfn[u],dfn[u])<<" "<<query(1,1,n,dfn[v],dfn[v]);
                cout<<" "<<query(1,1,n,dfn[lca],dfn[lca])<<" "<<lca<<endl;
				printf("%d\n",deep[u]+deep[v]-2*deep[lca]-x);
            }
        }
        for(int i=0;i<=n+1;++i){
            head[i]=deep[i]=size[i]=dfn[i]=0;
        }
        clear(1,1,n);
        lc.clear();
        tot=0; 
    }
    return 0;
}
posted @ 2021-08-08 20:05  comld  阅读(128)  评论(0编辑  收藏  举报