• 洛谷7735:[NOI2021] 轻重边——题解


    https://www.luogu.com.cn/problem/P7735

    网上的做法我找到的分两种,一种是染色法,这种做法好写,但是我不认为以我的脑子能想出来。另一种是暴力维护,因为易知与任何一点相关联的重边最多只有两条,好想不好写。

    当然这里就说下前者的做法。每次操作时相当于为路径上的所有点染上一种与众不同的颜色。而至于重边的判断,则是边的端点颜色相同(且不为0)。由此树链剖分维护即可。

    (这种做法是咋想到的啊……要不然就是我题刷少了QAQ)

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=1e5+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline int check(int l,int r){
        return (l==r)&&l;
    }
    struct Ans{
        int l,r,sum;
        Ans(){
            l=r=sum=0;
        }
        Ans(int _l,int _r,int _sum){
            l=_l;r=_r;sum=_sum;
        }
        Ans operator +(const Ans& b)const{
            int L=(!l)?b.l:l;
            int R=(!b.r)?r:b.r;
            return Ans(L,R,sum+b.sum+check(r,b.l));
        }
    };
    struct node{
        int to,nxt;
    }e[N<<1];
    struct tree{
        int lazy;
        Ans d;
    }t[N<<2];
    int head[N],cnt,tot,n,m,rt;
    int fa[N],pos[N],idx[N],son[N],size[N],dep[N],top[N];
    inline void add(int u,int v){
        e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    }
    void dfs1(int u){
        size[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(fa[u]==v)continue;
            fa[v]=u;dep[v]=dep[u]+1;
            dfs1(v);
            size[u]+=size[v];
            if(!son[u]||size[son[u]]<size[v])son[u]=v;
        }
    }
    void dfs2(int u,int anc){
        pos[u]=++tot;idx[tot]=u;top[u]=anc;
        if(!son[u])return;
        dfs2(son[u],anc);
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fa[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    inline void init(){
        dep[rt]=1;
        dfs1(rt);
        dfs2(rt,rt);
    }
    void build(int a,int l,int r){
        if(l==r){
            t[a].lazy=0;
            t[a].d=Ans();
            return;
        }
        int mid=(l+r)>>1;
        build(a<<1,l,mid);build(a<<1|1,mid+1,r);
        t[a].lazy=0;
        t[a].d=t[a<<1].d+t[a<<1|1].d;
    }
    void pushdown(int a,int l,int r){
        int mid=(l+r)>>1;
        if(t[a].lazy){
            t[a<<1].lazy=t[a].lazy;
            t[a<<1|1].lazy=t[a].lazy;
            t[a<<1].d=Ans(t[a].lazy,t[a].lazy,mid-l);
            t[a<<1|1].d=Ans(t[a].lazy,t[a].lazy,r-mid-1);
            t[a].lazy=0;
        }
        return;
    }
    inline Ans query(int a,int l,int r,int l1,int r1){
        if(r1<l||r<l1)return Ans();
        if(l1<=l&&r<=r1)return t[a].d;
        int mid=(l+r)>>1;pushdown(a,l,r);
        Ans tmp=query(a<<1,l,mid,l1,r1)+query(a<<1|1,mid+1,r,l1,r1);
        return tmp;
    }
    inline void modify(int a,int l,int r,int l1,int r1,int v){
        if(r1<l||r<l1)return;
        if(l1<=l&&r<=r1){
            t[a].lazy=v;
            t[a].d=Ans(v,v,r-l);
            return;
        }
        int mid=(l+r)>>1;pushdown(a,l,r);
        modify(a<<1,l,mid,l1,r1,v);modify(a<<1|1,mid+1,r,l1,r1,v);
        t[a].d=t[a<<1].d+t[a<<1|1].d;
    }
    inline int pathquery(int x,int y){
        int op=0;
        Ans ansl,ansr;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]){
                swap(x,y);op^=1;
            }
            if(!op) ansl=query(1,1,n,pos[top[x]],pos[x])+ansl;
            else ansr=query(1,1,n,pos[top[x]],pos[x])+ansr;
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]){
            swap(x,y);op^=1;
        }
        Ans ans=query(1,1,n,pos[x],pos[y]);
        swap(ansl.l,ansl.r);
        if(op)swap(ans.l,ans.r);
        ans=ansl+ans+ansr;
        return ans.sum;
    }
    inline void pathmodify(int x,int y,int z){
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            modify(1,1,n,pos[top[x]],pos[x],z);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])swap(x,y);
        modify(1,1,n,pos[x],pos[y],z);
    }
    void initforcase(){
        cnt=tot=0;rt=1;
        memset(head,0,sizeof(head));
        memset(son,0,sizeof(son));
    }
    int main(){
        int T=read();
        while(T--){
            initforcase();
            n=read(),m=read();
            for(int i=1;i<n;i++){
                int u=read(),v=read();
                add(u,v);add(v,u);
            }
            init();build(1,1,n);
            for(int i=1;i<=m;i++){
                int op=read();
                if(op==1){
                    int x=read(),y=read(),z=i;
                    pathmodify(x,y,z);
                }
                if(op==2){
                    int x=read(),y=read();
                    printf("%d
    ",pathquery(x,y));
                }
            }
        }
        
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    宏定义问题
    (转载)(int)a、&a、(int)&a、(int&)a的区别,很偏僻的题
    boolalpha的作用
    一些小细节
    HTTP Keep-Alive的作用
    数据库三大范式
    laravel 安装语言包
    MySQL存储引擎中的MyISAM和InnoDB区别详解
    推荐一款超好用的工具cmder
    如何保证代码质量
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/15088270.html
Copyright © 2020-2023  润新知