首页 > 代码库 > [BZOJ]4817: [Sdoi2017]树点涂色

[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\n",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\n",query(1,l[x],r[x])+1);
    }
}

[BZOJ]4817: [Sdoi2017]树点涂色