bzoj4817: [Sdoi2017]树点涂色

震惊!LCT还能这么用!

这个颜色修改的特点是点到根

搜刮一下性质,颜色从根到某个点是分层次单调增的,而且同一个点的两个不同儿子不会有相同颜色,也就是相同颜色的点是树上自上往下的一条链

前面这些都是次要的,主要是能不能想到并不和LCT的access操作很像

那么我们可以让一棵splay维护一条相同颜色的链,那么access修改儿子的时候顺便改一改点到根的颜色数

dfs序+线段树维护子树中的最大值

第二个问直接暴力跳链算就行了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int _=1e2;
const int maxn=1e5+_;
const int fbin=(1<<17)+_;
const int mbit=30;
int n;

int L[maxn],R[maxn];
struct segnode{int mx,la;};
struct segtree
{
    segnode tr[2*fbin];
    void pushdown(int now)
    {
        int lc=(now<<1),rc=(now<<1|1);
        if(tr[now].la!=0)
        {
            tr[lc].mx+=tr[now].la,tr[lc].la+=tr[now].la;
            tr[rc].mx+=tr[now].la,tr[rc].la+=tr[now].la;
            tr[now].la=0;
        }
    }
    void update(int now)
    {
        int lc=(now<<1),rc=(now<<1|1);
        tr[now].mx=max(tr[lc].mx,tr[rc].mx);
    }
    void change(int now,int ql,int qr,int l,int r,int c)
    {
        if(ql==l&&qr==r){tr[now].mx+=c,tr[now].la+=c;return ;}
        pushdown(now);
        int mid=(ql+qr)/2,lc=(now<<1),rc=(now<<1|1);
             if(r<=mid)  change(lc,ql,mid,l,r,c);
        else if(mid+1<=l)change(rc,mid+1,qr,l,r,c);
        else change(lc,ql,mid,l,mid,c),change(rc,mid+1,qr,mid+1,r,c);
        update(now);
    }
    int getmax(int now,int ql,int qr,int l,int r)
    {
        if(ql==l&&qr==r)return tr[now].mx;
        pushdown(now);
        int mid=(ql+qr)/2,lc=(now<<1),rc=(now<<1|1);
             if(r<=mid)  return getmax(lc,ql,mid,l,r);
        else if(mid+1<=l)return getmax(rc,mid+1,qr,l,r);
        else return max(getmax(lc,ql,mid,l,mid),getmax(rc,mid+1,qr,mid+1,r));
    }
}S;

struct trnode{int f,son[2];bool fz;};
struct LCT
{
    trnode tr[maxn];
    void rev(int x)
    {
        if(tr[x].fz)
        {
            int lc=tr[x].son[0],rc=tr[x].son[1];
            swap(tr[lc].son[0],tr[lc].son[1]),tr[lc].fz^=1;
            swap(tr[rc].son[0],tr[rc].son[1]),tr[rc].fz^=1;
            tr[x].fz=false;
        }
    }
    void rotate(int x,int w)
    {
        int f=tr[x].f,ff=tr[f].f;
        int R,r;
        
        R=f,r=tr[x].son[w];
        tr[R].son[1-w]=r;
        if(r!=0)tr[r].f=R;
        
        R=ff,r=x;
             if(tr[ff].son[0]==f)tr[R].son[0]=r;
        else if(tr[ff].son[1]==f)tr[R].son[1]=r;
        tr[r].f=R;
        
        R=x,r=f;
        tr[R].son[w]=r;
        tr[r].f=R;
    }
    int tlen,tmp[maxn];
    bool islight(int x)
    {
        if(tr[x].f==0||(tr[tr[x].f].son[0]!=x&&tr[tr[x].f].son[1]!=x))return true;
        return false;
    }
    void splay(int x,int rt)
    {
        tlen=0;int i=x;
        while(x!=rt&& !islight(i) )
            tmp[++tlen]=i,i=tr[i].f;
        tmp[++tlen]=i;
        while(tlen!=0)rev(tmp[tlen]),tlen--;
        
        while(tr[x].f!=rt&& !islight(x) )
        {
            int f=tr[x].f,ff=tr[f].f;
            if(ff==rt||islight(f))
            {
                if(tr[f].son[0]==x)rotate(x,1);
                else rotate(x,0);
            }
            else
            {
                     if(tr[ff].son[0]==f&&tr[f].son[0]==x)rotate(f,1),rotate(x,1);
                else if(tr[ff].son[1]==f&&tr[f].son[1]==x)rotate(f,0),rotate(x,0);
                else if(tr[ff].son[0]==f&&tr[f].son[1]==x)rotate(x,0),rotate(x,1);
                else if(tr[ff].son[1]==f&&tr[f].son[0]==x)rotate(x,1),rotate(x,0);
            }
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~splay~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    
    int findroot(int x)
    {
        splay(x,0);
        while(tr[x].son[0]!=0)x=tr[x].son[0];
        return x;
    }
    void access(int x)
    {
        int y=0,u,rt;
        while(x!=0)
        {
            splay(x,0);
            u=tr[x].son[1];
            if(y!=0)rt=findroot(y),S.change(1,1,n,L[rt],R[rt],-1);
            splay(x,0);
            tr[x].son[1]=y;
            if(u!=0)rt=findroot(u),S.change(1,1,n,L[rt],R[rt],1);
            y=x,x=tr[x].f;
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~lct~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    int getsum(int x,int z)
    {
        int ans=1;
        while(findroot(x)!=findroot(z))
        {
            splay(x,0);
            x=tr[x].f;
            ans++;
        }
        return ans;
    }
    
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~solve~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}lct;

//--------------------------------------------data structure--------------------------------------------------------------

struct node
{
    int x,y,next;
}a[2*maxn];int len,last[maxn];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int z,f[mbit][maxn],dep[maxn];
void dfs(int x)
{
    for(int i=1;(1<<i)<=dep[x];i++)f[i][x]=f[i-1][f[i-1][x]];
    L[x]=++z;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=f[0][x])
        {
            lct.tr[y].f=x;
            dep[y]=dep[x]+1;
            f[0][y]=x;
            dfs(y);
        }
    }
    R[x]=z;S.change(1,1,n,L[x],R[x],1);
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=25;i>=0;i--)
        if(dep[x]-dep[y]>=(1<<i))x=f[i][x];
    if(x==y)return x;
    for(int i=25;i>=0;i--)
        if(dep[x]>=(1<<i)&&f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
    return f[0][x];
}

//---------------------------------------true tree------------------------------------------------------------

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int Q,x,y;
    scanf("%d%d",&n,&Q); len=1;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        ins(x,y),ins(y,x);
    }
    dfs(1);
    
    int op;
    while(Q--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&x);
            lct.access(x);
        }
        else if(op==2)
        {
            scanf("%d%d",&x,&y);
            int z=LCA(x,y);
            printf("%d\n",lct.getsum(x,z)+lct.getsum(y,z)-1);
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",S.getmax(1,1,n,L[x],R[x]));
        }
    }
    
    return 0;
}

 

posted @ 2019-02-28 21:17  AKCqhzdy  阅读(180)  评论(0编辑  收藏  举报