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

    Time Limit: 10 Sec  Memory Limit: 128 MB

    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操作,输出一个数表示权值的最大值

    Sample 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

    Sample Output

      3
      4
      2
      2

    Solution

      发现这个修改操作像极了LCT,于是我们直接用LCT维护这棵树,每棵Splay代表一种颜色,每个点到根的权值就是到根路径上非偏爱边(这里非偏爱边相当于两端颜色不同的边)数量加一,一开始所有点的权值就是深度,当进行access操作时,我们每把一条偏爱边设成非偏爱边,就让这条边下面那棵子树权值加一,反之减一,以dfs序建线段树维护最大值即可,1操作直接access一遍,2操作等同于询问链上非偏爱边数加一,链上非偏爱边数即x到根的非偏爱边数+y到根的非偏爱边数-2*lca(x,y)到根的偏爱边数,3操作直接查。由于LCT是均摊O(nlogn)的,我们往里面每次操作都加了一个维护线段树的工作,总复杂度O(nlogn^2)。

    Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    char B[1<<26],*S=B,C;int X;
    inline int read()
    {
        while((C=*S++)<'0'||C>'9');
        for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=X*10+C-'0';
        return X;
    }
    #define MN 100000
    #define LG 17
    struct edge{int nx,t;}e[MN*2+5];
    int h[MN+5],en,fa[LG][MN+5],d[MN+5],a[MN+5],l[MN+5],r[MN+5],cnt;
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    namespace segtree
    {
        #define L (k<<1)
        #define R (k<<1|1)
        struct node{int l,r,mx,mk;}t[MN*4+5];
        inline void up(int k){t[k].mx=max(t[L].mx,t[R].mx);}
        inline void mark(int k,int x){t[k].mx+=x;t[k].mk+=x;}
        inline void down(int k){if(t[k].mk)mark(L,t[k].mk),mark(R,t[k].mk),t[k].mk=0;}
        void build(int k,int l,int r)
        {
            if((t[k].l=l)==(t[k].r=r)){t[k].mx=a[l];return;}
            int mid=l+r>>1;
            build(L,l,mid);build(R,mid+1,r);up(k);
        }
        void add(int k,int l,int r,int x)
        {
            if(t[k].l==l&&t[k].r==r){mark(k,x);return;}
            int mid=t[k].l+t[k].r>>1;down(k);
            if(r<=mid)add(L,l,r,x);
            else if(l>mid)add(R,l,r,x);
            else add(L,l,mid,x),add(R,mid+1,r,x);
            up(k);
        }
        int query(int k,int l,int r)
        {
            if(t[k].l==l&&t[k].r==r)return t[k].mx;
            int mid=t[k].l+t[k].r>>1;down(k);
            if(r<=mid)return query(L,l,r);
            if(l>mid)return query(R,l,r);
            return max(query(L,l,mid),query(R,mid+1,r));
        }
    }
    namespace lct
    {
        #define L(x) c[x][0]
        #define R(x) c[x][1]
        int fa[MN+5],c[MN+5][2],ll[MN+5];
        inline void up(int x){ll[x]=L(x)?ll[L(x)]:x;}
        inline bool isc(int x){return L(fa[x])==x||R(fa[x])==x;}
        void rotate(int x)
        {
            int f=fa[x],ff=fa[f],l=R(f)==x,r=l^1;
            if(isc(f))c[ff][R(ff)==f]=x;
            fa[f]=x;fa[x]=ff;fa[c[x][r]]=f;
            c[f][l]=c[x][r];up(c[x][r]=f);
        }
        void splay(int x)
        {
            for(int f;isc(x);rotate(x))
                if(isc(f=fa[x]))rotate(L(fa[f])==f^L(f)==x?x:f);
            up(x);
        }
        void access(int x)
        {
            for(int i=0,p;x;x=fa[i=x])
            {
                splay(x);
                if(R(x))segtree::add(1,l[ll[R(x)]],r[ll[R(x)]],1);
                if(i)segtree::add(1,l[ll[i]],r[ll[i]],-1);
                R(x)=i;
            }
        }
    }
    void dfs(int x)
    {
        a[l[x]=++cnt]=d[x];
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[0][x])
            lct::fa[e[i].t]=fa[0][e[i].t]=x,d[e[i].t]=d[x]+1,dfs(e[i].t);
        r[x]=cnt;
    }
    int lca(int x,int y)
    {
        int dx=d[x]-d[y],i;
        if(dx<0)swap(x,y),dx=-dx;
        for(i=0;dx;++i,dx>>=1)if(dx&1)x=fa[i][x];
        if(x==y)return x;
        for(i=LG;i--;)if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y];
        return fa[0][x];
    }
    int main()
    {
        fread(B,1,1<<26,stdin);
        int n,m,i,j,x,y,z;
        n=read();m=read();
        for(i=1;i<n;++i)ins(read(),read());
        dfs(1);segtree::build(1,1,n);
        for(i=1;i<LG;++i)for(j=1;j<=n;++j)fa[i][j]=fa[i-1][fa[i-1][j]];
        using segtree::query;
        while(m--)
        {
            i=read();
            if(i==1)lct::access(read());
            if(i==2)z=lca(x=read(),y=read()),
                printf("%d
    ",query(1,l[x],l[x])+query(1,l[y],l[y])-(query(1,l[z],l[z])<<1)+1);
            if(i==3)x=read(),printf("%d
    ",query(1,l[x],r[x])+1);
        }
    }
  • 相关阅读:
    HDU 2236 无题Ⅱ
    Golden Tiger Claw(二分图)
    HDU 5969 最大的位或 (思维,贪心)
    HDU 3686 Traffic Real Time Query System (图论)
    SCOI 2016 萌萌哒
    Spring Boot支持控制台Banner定制
    构建第一个Spring Boot程序
    Spring Boot重要模块
    Java fastjson JSON和String互相转换
    BCompare 4 Windows激活方法【试用期30天重置】
  • 原文地址:https://www.cnblogs.com/ditoly/p/BZOJ4817.html
Copyright © 2011-2022 走看看