ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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操作,输出一个数表示权值的最大值
由于染色都是从根开始的一条路径,可以发现:
操作1就是无换根操作的lct的access,操作2是查询给定路径经过lct中几条虚边,操作3是查询子树内到根的最大虚边条数
lct每次access均摊修改O(logn)条边的虚实,因此可以维护原树的lct方便操作1
树链剖分+树状数组维护路径上虚边条数
线段树维护dfs序,区间内点到根路径上最大虚边条数
于是每次修改边的类型时,对应在树状数组上单点修改,线段树上区间加
总复杂度O(mlog2(n))
#include<cstdio>
const int N=100007;
char buf[N*100],*ptr=buf-1;
int _(){
    int x=0,c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x;
}
int n,m,es[N*2],enx[N*2],e0[N],ep=2,dw[N];
int _l,_r,_a;
int max(int a,int b){return a>b?a:b;}
namespace SGT{
struct node{
    node*lc,*rc;
    int L,R,M;
    int mx,a;
    void _add(int x){
        mx+=x;a+=x;
    }
    void dn(){
        if(a){
            lc->_add(a);
            rc->_add(a);
            a=0;
        }
    }
    void up(){
        mx=max(lc->mx,rc->mx);
    }
    void add(){
        if(_l<=L&&R<=_r){
            _add(_a);
            return;
        }
        dn();
        if(_l<=M)lc->add();
        if(_r>M)rc->add();
        up();
    }
    int gmx(){
        if(_l<=L&&R<=_r)return mx;
        dn();
        if(_r<=M)return lc->gmx();
        if(_l>M)return rc->gmx();
        return max(lc->gmx(),rc->gmx());
    }
}ns[N*2],*np=ns,*rt;
node*build(int L,int R){
    node*w=np++;
    w->L=L;w->R=R;
    if(L<R){
        int M=w->M=L+R>>1;
        w->lc=build(L,M);
        w->rc=build(M+1,R);
    }
    return w;
}
}
namespace BIT{
int f[N];
void inc(int w,int x){
    for(;w<=n;w+=w&-w)f[w]+=x;
}
int sum(int w){
    int s=0;
    for(;w;w-=w&-w)s+=f[w];
    return s;
}
}
namespace HLD{
using namespace SGT;
using namespace BIT;
int fa[N],sz[N],son[N],dep[N],top[N],id[N],id2[N],idp=0;
void f1(int w,int pa){
    dep[w]=dep[fa[w]=pa]+1;
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]>sz[son[w]])son[w]=u;
        }
    }
}
void f2(int w,int tp){
    top[w]=tp;
    id[w]=++idp;
    if(son[w])f2(son[w],tp);
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=fa[w]&&u!=son[w])f2(u,u);
    }
    id2[w]=idp;
}
int lca(int x,int y){
    int a=top[x],b=top[y],s=1;
    while(a!=b){
        if(dep[a]>dep[b]){
            s+=BIT::sum(id[x])-BIT::sum(id[a]-1);
            x=fa[a],a=top[x];
        }else{
            s+=BIT::sum(id[y])-BIT::sum(id[b]-1);
            y=fa[b],b=top[y];
        }
    }
    if(dep[x]>dep[y])s+=BIT::sum(id[x])-BIT::sum(id[y]);
    if(dep[x]<dep[y])s+=BIT::sum(id[y])-BIT::sum(id[x]);
    return s;
}
void init(){
    f1(1,0);f2(1,1);
    rt=build(1,n);
    for(int i=2;i<=n;++i){
        inc(id[i],1);
        _l=id[i],_r=id2[i],_a=1;
        rt->add();
    }
}
int query(int x){
    _l=id[x],_r=id2[x];
    return rt->gmx()+1;
}
void setdw(int x,int y){
    if(dw[x]){
        inc(id[dw[x]],1);
        _l=id[dw[x]],_r=id2[dw[x]],_a=1;
        rt->add();
    }
    if(dw[x]=y){
        inc(id[y],-1);
        _l=id[y],_r=id2[y],_a=-1;
        rt->add();
    }
}
}
namespace LCT{
#define lc ch][0
#define rc ch][1
#define fa ch][2
int ch[N][4];
bool nrt(int x){return x==x[fa][lc]||x==x[fa][rc];}
void rot(int x){
    int f=x[fa],g=f[fa],d=(x!=f[lc]);
    if(nrt(f))g[ch][g[lc]!=f]=x;
    x[fa]=g;
    (f[ch][d]=x[ch][d^1])[fa]=f;
    (x[ch][d^1]=f)[fa]=x;
}
void sp(int x){
    while(nrt(x)){
        int f=x[fa];
        if(nrt(f))rot((x==f[lc])==(f==f[fa][lc])?f:x);
        rot(x);
    }
}
int gl(int x){
    while(x[lc])x=x[lc];
    sp(x);
    return x;
}
void acs(int x){
    for(int y=0;x;sp(x),HLD::setdw(x,y),x[rc]=y,y=gl(x),x=y[fa]);
}
#undef lc
#undef rc
#undef fa
}
int main(){
    fread(buf,1,sizeof(buf),stdin)[buf]=0;
    n=_();m=_();
    for(int i=1,a,b;i<n;++i){
        a=_();b=_();
        es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
        es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
    }
    HLD::init();
    for(int i=2;i<=n;++i)LCT::ch[i][2]=HLD::fa[i];
    for(int i=0,o,a,b;i<m;++i){
        o=_();
        if(o==1){
            a=_();
            LCT::acs(a);
        }else if(o==2){
            a=_();b=_();
            printf("%d\n",HLD::lca(a,b));
        }else{
            a=_();
            printf("%d\n",HLD::query(a));
        }
    }
    return 0;
}

 

posted on 2017-04-12 09:19  nul  阅读(460)  评论(0编辑  收藏  举报