zoukankan      html  css  js  c++  java
  • bzoj4817: [Sdoi2017]树点涂色

    Description

    Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
    径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
    1 x:
    把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
    2 x y:
    求x到y的路径的权值。
    3 x y:
    在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
    Bob一共会进行m次操作

    Input

    第一行两个数n,m。
    接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
    接下来m行,表示操作,格式见题目描述
    1<=n,m<=100000

    Output

    每当出现2,3操作,输出一行。
    如果是2操作,输出一个数表示路径的权值
    如果是3操作,输出一个数表示权值的最大值
    由于染色都是从根开始的一条路径,可以发现:
    操作1就是无换根操作的lct的access,操作2是查询给定路径经过lct中几条虚边,操作3是查询子树内到根的最大虚边条数
    lct每次access均摊修改O(logn)条边的虚实,因此可以维护原树的lct方便操作1
    树链剖分+树状数组维护路径上虚边条数
    线段树维护dfs序,区间内点到根路径上最大虚边条数
    于是每次修改边的类型时,对应在树状数组上单点修改,线段树上区间加
    总复杂度O(mlog2(n))
    #include<cstdio>
    const int N=100007;
    char buf[N*100],*ptr=buf-1;
    int _(){
        int x=0,c=*++ptr;
        while(c<48)c=*++ptr;
        while(c>47)x=x*10+c-48,c=*++ptr;
        return x;
    }
    int n,m,es[N*2],enx[N*2],e0[N],ep=2,dw[N];
    int _l,_r,_a;
    int max(int a,int b){return a>b?a:b;}
    namespace SGT{
    struct node{
        node*lc,*rc;
        int L,R,M;
        int mx,a;
        void _add(int x){
            mx+=x;a+=x;
        }
        void dn(){
            if(a){
                lc->_add(a);
                rc->_add(a);
                a=0;
            }
        }
        void up(){
            mx=max(lc->mx,rc->mx);
        }
        void add(){
            if(_l<=L&&R<=_r){
                _add(_a);
                return;
            }
            dn();
            if(_l<=M)lc->add();
            if(_r>M)rc->add();
            up();
        }
        int gmx(){
            if(_l<=L&&R<=_r)return mx;
            dn();
            if(_r<=M)return lc->gmx();
            if(_l>M)return rc->gmx();
            return max(lc->gmx(),rc->gmx());
        }
    }ns[N*2],*np=ns,*rt;
    node*build(int L,int R){
        node*w=np++;
        w->L=L;w->R=R;
        if(L<R){
            int M=w->M=L+R>>1;
            w->lc=build(L,M);
            w->rc=build(M+1,R);
        }
        return w;
    }
    }
    namespace BIT{
    int f[N];
    void inc(int w,int x){
        for(;w<=n;w+=w&-w)f[w]+=x;
    }
    int sum(int w){
        int s=0;
        for(;w;w-=w&-w)s+=f[w];
        return s;
    }
    }
    namespace HLD{
    using namespace SGT;
    using namespace BIT;
    int fa[N],sz[N],son[N],dep[N],top[N],id[N],id2[N],idp=0;
    void f1(int w,int pa){
        dep[w]=dep[fa[w]=pa]+1;
        sz[w]=1;
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa){
                f1(u,w);
                sz[w]+=sz[u];
                if(sz[u]>sz[son[w]])son[w]=u;
            }
        }
    }
    void f2(int w,int tp){
        top[w]=tp;
        id[w]=++idp;
        if(son[w])f2(son[w],tp);
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=fa[w]&&u!=son[w])f2(u,u);
        }
        id2[w]=idp;
    }
    int lca(int x,int y){
        int a=top[x],b=top[y],s=1;
        while(a!=b){
            if(dep[a]>dep[b]){
                s+=BIT::sum(id[x])-BIT::sum(id[a]-1);
                x=fa[a],a=top[x];
            }else{
                s+=BIT::sum(id[y])-BIT::sum(id[b]-1);
                y=fa[b],b=top[y];
            }
        }
        if(dep[x]>dep[y])s+=BIT::sum(id[x])-BIT::sum(id[y]);
        if(dep[x]<dep[y])s+=BIT::sum(id[y])-BIT::sum(id[x]);
        return s;
    }
    void init(){
        f1(1,0);f2(1,1);
        rt=build(1,n);
        for(int i=2;i<=n;++i){
            inc(id[i],1);
            _l=id[i],_r=id2[i],_a=1;
            rt->add();
        }
    }
    int query(int x){
        _l=id[x],_r=id2[x];
        return rt->gmx()+1;
    }
    void setdw(int x,int y){
        if(dw[x]){
            inc(id[dw[x]],1);
            _l=id[dw[x]],_r=id2[dw[x]],_a=1;
            rt->add();
        }
        if(dw[x]=y){
            inc(id[y],-1);
            _l=id[y],_r=id2[y],_a=-1;
            rt->add();
        }
    }
    }
    namespace LCT{
    #define lc ch][0
    #define rc ch][1
    #define fa ch][2
    int ch[N][4];
    bool nrt(int x){return x==x[fa][lc]||x==x[fa][rc];}
    void rot(int x){
        int f=x[fa],g=f[fa],d=(x!=f[lc]);
        if(nrt(f))g[ch][g[lc]!=f]=x;
        x[fa]=g;
        (f[ch][d]=x[ch][d^1])[fa]=f;
        (x[ch][d^1]=f)[fa]=x;
    }
    void sp(int x){
        while(nrt(x)){
            int f=x[fa];
            if(nrt(f))rot((x==f[lc])==(f==f[fa][lc])?f:x);
            rot(x);
        }
    }
    int gl(int x){
        while(x[lc])x=x[lc];
        sp(x);
        return x;
    }
    void acs(int x){
        for(int y=0;x;sp(x),HLD::setdw(x,y),x[rc]=y,y=gl(x),x=y[fa]);
    }
    #undef lc
    #undef rc
    #undef fa
    }
    int main(){
        fread(buf,1,sizeof(buf),stdin)[buf]=0;
        n=_();m=_();
        for(int i=1,a,b;i<n;++i){
            a=_();b=_();
            es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
            es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
        }
        HLD::init();
        for(int i=2;i<=n;++i)LCT::ch[i][2]=HLD::fa[i];
        for(int i=0,o,a,b;i<m;++i){
            o=_();
            if(o==1){
                a=_();
                LCT::acs(a);
            }else if(o==2){
                a=_();b=_();
                printf("%d
    ",HLD::lca(a,b));
            }else{
                a=_();
                printf("%d
    ",HLD::query(a));
            }
        }
        return 0;
    }
  • 相关阅读:
    Python高级特性-迭代
    Python列表生成式测试
    Python函数基础学习(定义、函数参数、递归函数)
    Html介绍,认识head标签
    Html介绍,认识html文件基本结构
    Html介绍,标签的语法
    Html介绍,认识html标签
    Html介绍,了解html与css关系
    Html介绍,如何用代码展示我制作的第一个网页?
    C++走向远洋——38(用对象数组操作长方柱类)
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6697579.html
Copyright © 2011-2022 走看看