• Luogu P3703 [SDOI2017]树点涂色


    比较有趣的综合树上问题,刷LCT题单时做的但是发现后面LCT只是起了辅助作用233

    首先我们分析每一个操作,(1)的定义就让我们联想到了access,我们回忆一下LCT的性质:

    LCT中每一个splay保存的都是原树上深度连续的一条链。

    那么我们发现由于这里的染色是染上全新的一种颜色,所以每一次access后的每棵splay维护的都是同种颜色的点链,是同时符合性质和题目要求的

    不过注意由于这里是染新的颜色,所以是可以用access的,如果是染成之前的某种颜色那么就不能这么做!

    好了想完修改我们来考虑询问,首先看(2)操作,询问路径的颜色个数?

    由于这是一棵有根树,结合前面的操作我们容易想到维护每个点到根节点的颜色个数记为(col_i)

    容易发现这里的(col)具有可减性,那么维护路径颜色个数就可以用树上差分

    具体的,路径(x,y)之间的颜色个数就是(col_x+col_y-2cdot col_{operatorname{LCA}(x,y)}+1)

    这个和求树上两点间距离类似,不过就是(operatorname{LCA})的颜色会被减两次所以要加回去

    然后就是(3)操作,我们发现当我们维护了(col)之后其实就是询问一个子树内最大的(col)

    子树信息想到什么,DFS序啊!结合前面的access时进行的也是子树修改,我们容易想到维护区间修改区间查最大值线段树,这样结合access的期望(log)复杂度是(O(nlog^2n))的(复杂度分析类似于LCT上的平衡树操作)

    那么就代码实现方面,DFS序都要写了,那么顺带写一下树剖吧,一般跳的比倍增快一些

    然后就是码农时刻了,建议把代码分块一下要不然很容易调死不出

    奉上近(200)行的CODE

    #include<cstdio>
    #include<cctype>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    const int N=100005;
    struct edge
    {
        int to,nxt;
    }e[N<<1]; int n,m,head[N],cnt,opt,x,y,fa,id[N],dep[N],dfn[N],size[N];
    class FileInputOutput
    {
        private:
            static const int S=1<<21;
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
            char Fin[S],Fout[S],*A,*B; int pt[15],Ftop;
        public:
            Tp inline void read(T& x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            Tp inline void write(T x)
            {
                if (!x) return (void)(pc('0'),pc('
    ')); RI ptop=0;
                while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
            #undef tc
            #undef pc
    }F;
    class Segment_Tree
    {
        private:
            struct Segment
            {
                int mx,tag;
            }node[N<<2];
            #define M(x) node[x].mx
            #define T(x) node[x].tag
            inline int max(CI a,CI b)
            {
                return a>b?a:b;
            }
            inline void add(CI now,CI mv)
            {
                M(now)+=mv; T(now)+=mv;
            }
            inline void pushup(CI now)
            {
                M(now)=max(M(now<<1),M(now<<1|1));
            }
            inline void pushdown(CI now)
            {
                if (T(now)) add(now<<1,T(now)),add(now<<1|1,T(now)),T(now)=0;
            }
        public:
            #define TN CI now=1,CI l=1,CI r=n
            inline void build(TN)
            {
                if (l==r) return (void)(M(now)=dep[id[l]]); int mid=l+r>>1;
                build(now<<1,l,mid); build(now<<1|1,mid+1,r); pushup(now);
            }
            #define O beg,end
            inline void modify(CI beg,CI end,CI mv,TN)
            {
                if (beg<=l&&r<=end) return add(now,mv); int mid=l+r>>1; pushdown(now);
                if (beg<=mid) modify(O,mv,now<<1,l,mid); if (end>mid) modify(O,mv,now<<1|1,mid+1,r); pushup(now);
            }
            inline int query(CI beg,CI end,TN)
            {
                if (beg<=l&&r<=end) return M(now); int mid=l+r>>1,ret=0; pushdown(now);
                if (beg<=mid) ret=max(ret,query(O,now<<1,l,mid)); if (end>mid) ret=max(ret,query(O,now<<1|1,mid+1,r)); return ret;
            }
            #undef TN
            #undef O
            #undef M
            #undef T
    }T;
    class Link_Cut_Tree
    {
        private:
            struct splay
            {
                int ch[2],fa;
            }node[N];
            #define lc(x) node[x].ch[0]
            #define rc(x) node[x].ch[1]
            #define fa(x) node[x].fa
            inline void connect(CI x,CI y,CI d)
            {
                node[fa(x)=y].ch[d]=x;
            }
            inline int identify(CI now)
            {
                return rc(fa(now))==now;
            }
            inline bool isroot(CI now)
            {
                return lc(fa(now))!=now&&rc(fa(now))!=now;
            }
            inline void rotate(CI now)
            {
                int x=fa(now),y=fa(x),d=identify(now); if (!isroot(x)) node[y].ch[identify(x)]=now;
                fa(now)=y; connect(node[now].ch[d^1],x,d); connect(x,now,d^1);
            }
            inline void splay(int now)
            {
                for (int t;!isroot(now);rotate(now))
                t=fa(now),!isroot(t)&&(rotate(identify(now)!=identify(t)?now:t),0);
            }
            inline int findroot(int now)
            {
                while (lc(now)) now=lc(now); return now;
            }
        public:
            inline void link(CI x,CI y)
            {
                fa(x)=y;
            }
            inline void access(int x)
            {
                for (int y=0,t;x;x=fa(y=x))
                {
                    splay(x); if (rc(x)) t=findroot(rc(x)),T.modify(dfn[t],dfn[t]+size[t]-1,1);
                    if (rc(x)=y) t=findroot(rc(x)),T.modify(dfn[t],dfn[t]+size[t]-1,-1);
                }
            }
            #undef lc
            #undef rc
            #undef fa
    }LCT;
    class Light_Heavy_Division
    {
        private:
            int idx,top[N],father[N],son[N];
            inline void swap(int& x,int& y)
            {
                int t=x; x=y; y=t;
            }
        public:
            #define to e[i].to
            inline void DFS1(CI now,CI fa)
            {
                size[now]=1; dep[now]=dep[fa]+1; father[now]=fa;
                for (RI i=head[now];i;i=e[i].nxt) if (to!=fa)
                {
                    DFS1(to,now); size[now]+=size[to]; LCT.link(to,now);
                    if (size[to]>size[son[now]]) son[now]=to;
                }
            }
            inline void DFS2(CI now,CI tf)
            {
                id[dfn[now]=++idx]=now; top[now]=tf;
                if (son[now]) DFS2(son[now],tf);
                for (RI i=head[now];i;i=e[i].nxt)
                if (to!=father[now]&&to!=son[now]) DFS2(to,to);
            }
            inline int get_LCA(int x,int y)
            {
                while (top[x]!=top[y])
                {
                    if (dep[top[x]]<dep[top[y]]) swap(x,y);
                    x=father[top[x]];
                }
                return dep[x]<dep[y]?x:y;
            }
            #undef to
    }L;
    inline void add(CI x,CI y)
    {
        e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i; for (F.read(n),F.read(m),i=1;i<n;++i) F.read(x),F.read(y),add(x,y),add(y,x);
        for (L.DFS1(1,0),L.DFS2(1,1),T.build(),i=1;i<=m;++i)
        {
            F.read(opt); F.read(x); switch (opt)
            {
                case 1:
                    LCT.access(x); break;
                case 2:
                    F.read(y); fa=L.get_LCA(x,y);
                    F.write(T.query(dfn[x],dfn[x])+T.query(dfn[y],dfn[y])-
                    (T.query(dfn[fa],dfn[fa])<<1)+1); break;
                case 3:
                    F.write(T.query(dfn[x],dfn[x]+size[x]-1)); break;
            }
        }
        return F.Fend(),0;
    }
    
  • 相关阅读:
    认识弹性盒子
    管理Linux服务器的用户和组(续篇)
    管理Linux服务器的用户和组
    centos7 mysql数据库安装和配置
    熟练使用Linux进程管理类命令
    熟练使用Linux系统信息类命令
    Linux操作系统-基本命令(二)
    Linux操作系统-基本命令(一)
    api接口统一封装
    10分钟,让你彻底明白Promise原理
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10421989.html
Copyright © 2020-2023  润新知