• SDOI2017 树点染色


    \[SDOI2017 树点染色 \]

    • 题目描述
      Bob 有一棵 $ n $ 个点的有根树,其中 $ 1 $ 号点是根节点。Bob 在每个节点上涂了颜色,并且每个点上的颜色不同。
      定义一条路径的权值是,这条路径上的点(包括起点和终点)共有多少种不同的颜色。
      Bob 可能会进行这几种操作:

    • $ 1 \ x $,把点 $ x $ 到根节点的路径上的所有的点染上一种没有用过的新颜色;

    • $ 2 \ x \ y $,求 $ x $ 到 $ y $ 的路径的权值;

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

    • Bob 一共会进行 $ m $ 次操作。

    • 样例输入输出

    input
    5 6
    1 2
    2 3
    3 4
    3 5
    2 4 5
    3 3
    1 4
    2 4 5
    1 5
    2 4 5
    
    output
    3
    4
    2
    2
    
    • 数据范围
      \(n \leq 10^5,m \leq 10^5\)

    • 题解
      考虑定义\(fa(x)\)如果\(x\)与父节点颜色相同就是1,否则为0,强行定义\(fa(1) = 1\)
      几率\(dis(x)\)表示从\(x\)到1路径所有的\(fa(x)\)的和,那么就是路径权值。
      操作1需要你支持一系列\(fa(x)\)的修改,并且同时维护\(dis(x)\)
      操作2访问\(x,y\)答案就是\(dis(x) + dis(y) - (2 \times (dis(lca))) + 1\)
      操作3求最大的\(dis(x)\)
      操作1可以通过\(LCT\)\(Access\)操作实现。
      操作2和3可以用链剖+线段树维护信息。
      总评,数据结构板题。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100010;
    int n,m,tot,cnt,Next[N<<1],head[N],tree[N<<1],Fa[N],fa[N],dep[N],size[N],Son[N],tid[N],NUM[N],top[N],Max[N*4],lazy[N*4],son[N][2];
    void add(int x,int y)
    {
        tot++;
        Next[tot]=head[x];
        head[x]=tot;
        tree[tot]=y;
    }
    void dfs(int u,int father,int depth)
    {
        Fa[u]=fa[u]=father;dep[u]=depth;size[u]=1;Son[u]=0;
        int maxsize=0;
        for (int i=head[u];i;i=Next[i])
        {
            int v=tree[i];
            if (v==fa[u]) continue;
            dfs(v,u,depth+1);
            size[u]+=size[v];
            if (size[v]>maxsize)
            {
                maxsize=size[v];
                Son[u]=v;
            }
        }
    }
    void dfs1(int u,int ancestor)
    {
        tid[u]=++cnt;NUM[cnt]=u;top[u]=ancestor;
        if (Son[u]) dfs1(Son[u],ancestor);
        for (int i=head[u];i;i=Next[i])
            if (tree[i]!=fa[u]&&tree[i]!=Son[u]) dfs1(tree[i],tree[i]);
    }
    void build(int l,int r,int id)
    {
        if (l==r) { Max[id]=dep[NUM[l]];return;}
        int mid=(l+r)>>1;
        build(l,mid,id<<1);
        build(mid+1,r,id<<1|1);
        Max[id]=max(Max[id<<1],Max[id<<1|1]);
    }
    void down(int id)
    {
        if (lazy[id]!=0)
        {
            Max[id<<1]+=lazy[id];
            Max[id<<1|1]+=lazy[id];
            lazy[id<<1]+=lazy[id];
            lazy[id<<1|1]+=lazy[id];
            lazy[id]=0;
        }
    }
    void change(int l,int r,int id,int x,int y,int d)
    {
        if (l>y||r<x) return;
        if (l!=r) down(id);
        if (x<=l&&r<=y)
        {
            Max[id]+=d;
            lazy[id]+=d;
            return;
        }
        int mid=(l+r)>>1;
        change(l,mid,id<<1,x,y,d);
        change(mid+1,r,id<<1|1,x,y,d);
        Max[id]=max(Max[id<<1],Max[id<<1|1]);
    }
    int query_max(int l,int r,int id,int x,int y)
    {
        if (l>y||r<x) return 0;
        if (l!=r) down(id);
        if (x<=l&&r<=y) return Max[id];
        int mid=(l+r)>>1;
        return max(query_max(l,mid,id<<1,x,y),query_max(mid+1,r,id<<1|1,x,y));
    }
    int query_sum(int l,int r,int id,int x)
    {
        if (l>x||r<x) return 0;
        if (l!=r) down(id);
        if (l==r&&l==x) return Max[id];
        int mid=(l+r)>>1;
        return query_sum(l,mid,id<<1,x)+query_sum(mid+1,r,id<<1|1,x);
    }
    int LCA(int x,int y)
    {
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            x=Fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        return x;
    }
    int Query(int x)
    {
        return query_sum(1,n,1,tid[x]);
    }
    inline bool isRoot(int x) { return (son[fa[x]][0]!=x)&&(son[fa[x]][1]!=x);}
    inline void Rotate(int x)
    {
        int y=fa[x],z=fa[y],l,r;
        if (son[y][0]==x) l=0;else l=1;
        r=l^1;
        if (!isRoot(y))
        {
            if (son[z][0]==y) son[z][0]=x;else son[z][1]=x;
        }
        fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
        son[y][l]=son[x][r];son[x][r]=y;
    }
    inline void splay(int x)
    {
        while (!isRoot(x))
        {
            int y=fa[x],z=fa[y];
            if (!isRoot(y))
            {
                if ((son[z][0]==y)^(son[y][0]==x)) Rotate(x);
                    else Rotate(y);
            }
            Rotate(x);
        }
    }
    inline void access(int x)
    {
        for (int i=0;x;i=x,x=fa[x])
        {
            splay(x);
            if (son[x][1])
            {
                int id=son[x][1];
                while (son[id][0]) id=son[id][0];
                change(1,n,1,tid[id],tid[id]+size[id]-1,1);
            }
            if (i)
            {
                int id=i;
                while (son[id][0]) id=son[id][0];
                change(1,n,1,tid[id],tid[id]+size[id]-1,-1);
            }
            son[x][1]=i;
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        tot=cnt=0;
        for (int i=1;i<=n-1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs(1,0,1);
        dfs1(1,1);
        build(1,n,1);
        while (m--)
        {
            int id,x,y;
            scanf("%d",&id);
            if (id==1) { scanf("%d",&x);access(x);}
            if (id==2) { scanf("%d%d",&x,&y);printf("%d\n",Query(x)+Query(y)-Query(LCA(x,y))*2+1);}
            if (id==3) { scanf("%d",&x);printf("%d\n",query_max(1,n,1,tid[x],tid[x]+size[x]-1));}
        }
        return 0;
    }
    
    
  • 相关阅读:
    Android 浅谈相机研发
    Android线程和线程池
    android之多媒体篇(三)
    android之多媒体篇(二)
    android之多媒体篇(一)
    Android图片缩放方法
    android之BitmapFactory.Options的使用
    mac .bash_profile环境变量汇总
    免费的HTML5连载来了《HTML5网页开发实例具体解释》连载(六)媒体查询
    LeetCode
  • 原文地址:https://www.cnblogs.com/akoasm/p/10133984.html
Copyright © 2020-2023  润新知