树点涂色

 我们定义f(x),表示x与fa[x]的颜色是否相同,相同为0,不同为1,令 f(1)=1。g(x)表示x到root路径上的f的和。然后考虑怎么维护g(x)。 

 对于操作1,用LCT中的access操作来维护。

对于操作2,直接线段树查询。

对于操作3,维护一个最大值,然后区间查询最大值就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 400010
using namespace std;
int point[N],nxt[N],v[N],tr[N],delta[N],l[N],r[N],deep[N],mi[20];
int n,m,k,col[N],f[N][20],fa[N],ch[N][3],tot,sz,pos[N],cur[N];
void add(int x,int y){
    tot++;nxt[tot]=point[x];point[x]=tot;v[tot]=y;
    tot++;nxt[tot]=point[y];point[y]=tot;v[tot]=x;
}
void dfs(int rt){
    int x=rt; 
    while (true) {
        if (!deep[x]) {
            deep[x]=deep[f[x][0]]+1; 
            for (int i=1;i<=17;i++) {
                if (deep[x]-mi[i]<0) break;
                f[x][i]=f[f[x][i-1]][i-1];
            }
            l[x]=r[x]=++sz; pos[sz]=x; cur[x]=point[x];
        }
        bool pd=false;
        for (int i=cur[x];i;i=nxt[i]) {
            cur[x]=nxt[i];
            if (v[i]!=f[x][0]) {
                f[v[i]][0]=fa[v[i]]=x; x=v[i]; pd=true;
                break;
            }
        }
        if (!pd) {
            int t=f[x][0];// cout<<t<<endl;
            r[t]=max(r[t],r[x]);
            if (x==rt)  break;
            x=t;
        }
    }
}
int lca(int x,int  y){
    if (deep[x]<deep[y]) swap(x,y);
    int k=deep[x]-deep[y];
    for (int i=0;i<=17;i++)
     if ((k>>i)&1) x=f[x][i];
    if (x==y) return x;
    for (int i=17;i>=0;i--)
     if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
void update(int now){
    tr[now]=max(tr[now<<1],tr[now<<1|1]);
}
void pushdown(int now){
    if (delta[now]) {
        tr[now<<1]+=delta[now]; tr[now<<1|1]+=delta[now];
        delta[now<<1]+=delta[now]; delta[now<<1|1]+=delta[now];
        delta[now]=0;
    }
}
void change(int now,int l,int r,int ll,int rr,int val){
    if (ll<=l&&r<=rr) {
        tr[now]+=val; delta[now]+=val;
        return;
    }
    int mid=(l+r)/2; 
    pushdown(now);
    if (ll<=mid) change(now<<1,l,mid,ll,rr,val);
    if (rr>mid) change(now<<1|1,mid+1,r,ll,rr,val);
    update(now);
}
int find(int now,int l,int r,int x){
    if (l==r) return tr[now];
    int mid=(l+r)/2;
    pushdown(now);
    if (x<=mid) return find(now<<1,l,mid,x);
    else return find(now<<1|1,mid+1,r,x);
}
int query(int now,int l,int r,int ll,int rr){
    if (ll<=l&&r<=rr) return tr[now];
    int mid=(l+r)/2; int ans=0;
    pushdown(now);
    if (ll<=mid) ans=max(ans,query(now<<1,l,mid,ll,rr));
    if (rr>mid) ans=max(ans,query(now<<1|1,mid+1,r,ll,rr));
    return ans;}
bool isroot(int x){
    return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
}
int get(int x){
    return ch[fa[x]][1]==x;
}
void rotate(int x){
    int y=fa[x]; int z=fa[y]; int which=get(x);
    if (!isroot(y)) ch[z][ch[z][1]==y]=x;
    fa[x]=z; fa[y]=x; ch[y][which]=ch[x][which^1];
    fa[ch[x][which^1]]=y; ch[x][which^1]=y;
}
void splay(int x){
    int y;
    while (!isroot(x)){
        y=fa[x];
        if (!isroot(y)) rotate(get(y)==get(x)?y:x);
        rotate(x);
    }
}
int get_root(int x){
    while (ch[x][0]) x=ch[x][0];
    return x;
}
void access(int x){
    int t=0;
    while (x) {
        col[x]=k;
        splay(x);
        int t1=get_root(ch[x][1]);
        if (t1) change(1,1,n,l[t1],r[t1],1);
        ch[x][1]=t;
        int t2=get_root(t);
        if (t2) change(1,1,n,l[t2],r[t2],-1);
        t=x; x=fa[x];
    }
}
int main(){
    scanf("%d%d",&n,&m); k=n; mi[0]=1;
    for (int i=1;i<=18;i++) mi[i]=mi[i-1]*2;
    for (int i=1;i<n;i++) {
        int x,y; scanf("%d%d",&x,&y);
        add(x,y);
    }
    dfs(1);
    for (int i=1;i<=n;i++) change(1,1,n,l[i],r[i],1);
    for (int i=1;i<=m;i++) {
        int opt,x,y; scanf("%d%d",&opt,&x);
        if (opt==1) k++,access(x);
        if (opt==2) {
            scanf("%d",&y); int t=lca(x,y);
            printf("%d
",find(1,1,n,l[x])+find(1,1,n,l[y])-2*find(1,1,n,l[t])+1);
        }
        if (opt==3) printf("%d
",query(1,1,n,l[x],r[x]));
    }
}
原文地址:https://www.cnblogs.com/harden/p/6701749.html