zoukankan      html  css  js  c++  java
  • [SDOI2017]树点涂色

    Description:

    Bob有一棵(n)个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。

    定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。

    Bob可能会进行这几种操作:

    (1) (x)

    把点(x)到根节点的路径上所有的点染上一种没有用过的新颜色。

    (2) (x) (y)

    (x)(y)的路径的权值。

    (3) (x)

    在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

    Bob一共会进行(m)次操作

    Hint:

    (n,mle 10^5)

    solution:

    首先我们需要维护每个点到根的权值

    2 操作可以直接 (dis_u+dis_v-2*dis_{LCA}+1)

    3 操作用线段树维护子树最值

    但直接做的话每次修改会把一条路径上的所有节点的子树都改一遍

    单次 (nlogn) 复杂度爆炸

    考虑其实一条路径上是若干段连续的颜色相等的区间

    如果能维护这个东西 复杂度就可以变成 (O(Color*logn) approx O(log^2n))

    因为每种颜色都是一条链 想到用 (LCT) 的每颗(splay) 维护一种颜色

    这样我们修改时就方便得多

    每次对一个点 (access)

    对于父亲节点之前的儿子的子树权值整体 (+1)

    对于当前节点子树权值整体 (-1)

    就可以了 复杂度 (O(nlog^2n))

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const int mxn=1e5+5;
    int n,m,cnt,hd[mxn],fa[mxn],ch[mxn][2];
    
    struct ed {
        int to,nxt;
    }t[mxn<<1];
    
    inline void add(int u,int v) {
        t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
    }
    
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
        return x*f;
    }
    inline void chkmax(int &x,int y) {if(x<y) x=y;}
    inline void chkmin(int &x,int y) {if(x>y) x=y;}
    
    int tot,f[mxn],sz[mxn],rk[mxn],top[mxn],son[mxn],dep[mxn],dfn[mxn];
    int tr[mxn<<2],tag[mxn<<2];
    
    namespace Seg {
        void push_up(int p) {
            tr[p]=max(tr[ls],tr[rs]);
        }
        void push_down(int p) {
            if(tag[p]) {
                tag[ls]+=tag[p];
                tag[rs]+=tag[p];
                tr[ls]+=tag[p];
                tr[rs]+=tag[p];
                tag[p]=0;
            }
        }
        void dfs1(int u,int fa) {
            dep[u]=dep[fa]+1; f[u]=fa; sz[u]=1;
            for(int i=hd[u];i;i=t[i].nxt) {
                int v=t[i].to;
                if(v==fa) continue ;
                dfs1(v,u); sz[u]+=sz[v];
                if(sz[son[u]]<sz[v]) son[u]=v;
            }
        }
        void dfs2(int u,int tp) {
            dfn[u]=++tot; rk[tot]=u; top[u]=tp;
            if(son[u]) dfs2(son[u],tp),fa[son[u]]=u;
            for(int i=hd[u];i;i=t[i].nxt) {
                int v=t[i].to;
                if(v==f[u]||v==son[u]) continue ;
                dfs2(v,v); fa[v]=f[v];
            }
        }
        void build(int l,int r,int p) {
            if(l==r) {
                tr[p]=dep[rk[l]];
                return ;
            }
            int mid=(l+r)>>1;
            build(l,mid,ls);
            build(mid+1,r,rs);
            push_up(p);
        }
        int LCA(int x,int y) {
            while(top[x]!=top[y]) {
                if(dep[top[x]]<dep[top[y]]) swap(x,y);
                x=f[top[x]];
            }
            return dep[x]<dep[y]?x:y;
        }
        void update(int l,int r,int ql,int qr,int val,int p) {
            if(ql<=l&&r<=qr) {
                tr[p]+=val;
                tag[p]+=val;
                return ;
            }
            int mid=(l+r)>>1; push_down(p);
            if(ql<=mid) update(l,mid,ql,qr,val,ls);
            if(qr>mid) update(mid+1,r,ql,qr,val,rs);
            push_up(p);
        }
        int query(int l,int r,int ql,int qr,int p) {
            if(ql<=l&&r<=qr) return tr[p];
            int mid=(l+r)>>1; push_down(p); int res=0;
            if(ql<=mid) chkmax(res,query(l,mid,ql,qr,ls));
            if(qr>mid) chkmax(res,query(mid+1,r,ql,qr,rs));
            push_up(p); return res;
        }
        int ask(int x) {return query(1,n,dfn[x],dfn[x],1);}
    }
    using namespace Seg;
    
    namespace lct {
        int isnotrt(int x) {
            return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
        }
        void rotate(int x) {
            int y=fa[x],z=fa[y],tp=ch[y][1]==x;
            if(isnotrt(y)) ch[z][ch[z][1]==y]=x; fa[x]=z;
            ch[y][tp]=ch[x][tp^1]; fa[ch[x][tp^1]]=y;
            ch[x][tp^1]=y; fa[y]=x;
        }
        void splay(int x) {
            while(isnotrt(x)) {
                int y=fa[x],z=fa[y];
                if(isnotrt(y)) 
                    (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
                rotate(x);	
            }
        }
        void access(int x) {
            for(int y=0;x;x=fa[y=x]) {
                splay(x);
                if(ch[x][1]) { //这里是本题重点
                    int pos=ch[x][1]; while(ch[pos][0]) pos=ch[pos][0];
                    update(1,n,dfn[pos],dfn[pos]+sz[pos]-1,1,1);
                }
                ch[x][1]=y;
                if(ch[x][1]) {
                    int pos=ch[x][1]; while(ch[pos][0]) pos=ch[pos][0];
                    update(1,n,dfn[pos],dfn[pos]+sz[pos]-1,-1,1);
                }
            }
        }
    }
    using namespace lct;
    
    int main()
    {
        n=read(); m=read(); int opt,x,y,u,v;
        for(int i=1;i<n;++i) {
            u=read(); v=read();
            add(u,v); add(v,u);
        }
        dfs1(1,0); dfs2(1,1); build(1,n,1);
        for(int i=1;i<=m;++i) {
            opt=read();
            if(opt==1) x=read(),access(x);
            else if(opt==2) {
                x=read(); y=read(); int lca=LCA(x,y);
                printf("%d
    ",ask(x)+ask(y)-2*ask(lca)+1);
            }
            else x=read(),printf("%d
    ",query(1,n,dfn[x],dfn[x]+sz[x]-1,1));
        }
        return 0;
    }
    
    
  • 相关阅读:
    学用MVC4做网站六后台管理:6.1.3管理员修改密码
    学用MVC4做网站六后台管理:6.1.1管理员登录、6.1.2退出
    学用MVC4做网站六后台管理:6.1管理员(续)
    学用MVC4做网站六:后台管理(续)
    SiteCore Experience Analytics-路径分析地图
    sitecore教程路径分析器
    SiteCore Experience Analytics-体验分析
    sitecore系列教程之更改您的个人设置
    sitecore中的两种编辑工具介绍
    Sitecore CMS中如何管理默认字段值
  • 原文地址:https://www.cnblogs.com/list1/p/10470047.html
Copyright © 2011-2022 走看看