• 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
    ",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;
    }
    
  • 相关阅读:
    SQL查询效率注意事项 2011.12.27
    MSSQL2005数据库快照(SNAPSHOT)初探
    恢复Intellij idea删除的文件
    因样式冲突引起的div消失问题
    C# 用面向对象的思想去编程
    C# Combobox联动
    C#端加载数据库,Combobox与Node控件绑定数据源demo示例
    数据库无法打开到SQL Server连接
    SQLServer2008 远程过程调用失败
    将.db文件导入SQLServer2008数据库
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/15115979.html
Copyright © 2020-2023  润新知