BZOJ4817[Sdoi2017]树点涂色

传送门

sdoi是真的舒服QAQ

比较神奇的数据结构上树题233

我们观察这个题的性质 发现将一条到1的路径染色很像LCT的access操作 我们不妨将相同颜色的点放在一个splay里面 然后access的时候 一条重边变成轻边的时候其实是 子树内ans +1 可以理解成原来它和它上面的节点颜色原本是相同的 然后断开边表示颜色不同了 轻边变成重边 子树内ans -1 原因同理 于是我们首先需要LCT来维持树的结构

子树内加减->我会dfs序上线段树! 于是我们可以用线段树维护子树内答案 询问3就变成了区间rmq

我们剩下了询问2 询问2怎么做呢? 路径问题! 树上差分!

我们发现这个“权值”也是满足树上差分的性质的 我们可以对其维护它到1号点的ans记为f[i]

于是第二问的答案就是f[x]+f[y]-2*f[lca]+1 (比较神奇 无论lca的颜色是否存在在路径上都是满足这个差分的)

所以我们最后只需要LCT维护树的形态 然后dfs序上线段树维护f 单点查询&区间查询大小值即可QwQ

附代码。(我的代码真的好看233)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define mxn 100010
#define lson x<<1
#define rson x<<1|1
#define fa(x) t[x].fa
#define ls(x) t[x].son[0]
#define rs(x) t[x].son[1]
#define not_root(x) (ls(fa(x))==x||rs(fa(x))==x)
#define ll long long
#define lg 18
using namespace std;

struct node{int son[2],fa;bool rev;}t[mxn];
struct edge{int to,lt;}e[mxn<<1];
int in[mxn],cnt,dep[mxn],dfn[mxn],tot;
int ff[mxn],n,sz[mxn],fa[mxn][lg+1],d[mxn];
struct Segtree
{
    int mx[mxn<<2],tag[mxn<<2];
    void pushup(int x){mx[x]=max(mx[lson],mx[rson]);}
    void pushdown(int x)
    {
        if(tag[x])
        {
            mx[lson]+=tag[x];
            tag[lson]+=tag[x];
            mx[rson]+=tag[x];
            tag[rson]+=tag[x];
            tag[x]=0;
        }
    }
    void build(int x,int l,int r)
    {
        if(l==r){mx[x]=ff[d[l]];return;}
        int mid=(l+r)>>1;
        build(lson,l,mid);build(rson,mid+1,r);
        pushup(x);
    }
    void modify(int x,int l,int r,int LL,int RR,int v)
    {
        if(l>=LL&&r<=RR){mx[x]+=v;tag[x]+=v;return;}
        int mid=(l+r)>>1;pushdown(x);
        if(LL<=mid)	modify(lson,l,mid,LL,RR,v);
        if(RR>mid)	modify(rson,mid+1,r,LL,RR,v);
        pushup(x);
    }
    int query(int x,int l,int r,int LL,int RR)
    {
        if(l>=LL&&r<=RR)	return mx[x];
        int mid=(l+r)>>1,ans=0;pushdown(x);
        if(LL<=mid)	ans=max(ans,query(lson,l,mid,LL,RR));
        if(RR>mid)	ans=max(ans,query(rson,mid+1,r,LL,RR));
        return ans;
    }
    int getans(int x)
    {
        return query(1,1,n,dfn[x],dfn[x]);
    }
}T;

void add(int x,int y)
{
    e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;
    e[++cnt].to=x;e[cnt].lt=in[y];in[y]=cnt;
}

void rotate(int x)
{
    if(!x||!not_root(x))	return;
    int f=fa(x),gf=fa(f);
    int k=rs(f)==x,p=k^1;
    if(not_root(f))	t[gf].son[t[gf].son[1]==f]=x;
    t[x].fa=gf;t[f].fa=x;
    t[f].son[k]=t[x].son[p];
    if(t[x].son[p])	t[t[x].son[p]].fa=f;
    t[x].son[p]=f;
}

void splay(int x)
{
    while(not_root(x))
    {
        int f=fa(x),gf=fa(f);
        if(not_root(gf))
            (rs(f)==x)^(rs(gf)==f)?rotate(x):rotate(f);
        rotate(x);
    }
}

int findroot(int x)
{
    while(ls(x))	x=ls(x);
    return x;
}

void access(int x)
{
    int y=0,w;
    do
    {
        splay(x);
        if(rs(x))	w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,1);
        t[x].son[1]=y;
        if(rs(x))	w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,-1);
        y=x;x=t[x].fa;
    }while(x);
}

void dfs(int x)
{
    ff[x]=dep[x];dfn[x]=++tot;d[tot]=x;sz[x]=1;t[x].fa=fa[x][0];
    for(int i=1;i<=lg;i++)	fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=in[x];i;i=e[i].lt)
    {
        int y=e[i].to;
        if(dep[y])	continue;
        dep[y]=dep[x]+1;fa[y][0]=x;
        dfs(y);sz[x]+=sz[y];
    }
}

int jump(int x,int len)
{
    for(int i=0;i<=lg;i++)
        if(len&(1<<i))
            x=fa[x][i];
    return x;
}

int lca(int x,int y)
{
    if(dep[x]<dep[y])	swap(x,y);
    x=jump(x,dep[x]-dep[y]);
    if(x==y)	return x;
    for(int i=lg;~i;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int query(int x,int y)
{
    return T.getans(x)+T.getans(y)-2*T.getans(lca(x,y))+1;
}

void modify(int x){access(x);}

int qmax(int x)
{
    return T.query(1,1,n,dfn[x],dfn[x]+sz[x]-1);
}

int main()
{
    int m,x,y,opt;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    dep[1]=1;dfs(1);T.build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&x);
            modify(x);
        }
        if(opt==2)
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",query(x,y));
        }
        if(opt==3)
        {
            scanf("%d",&x);
            printf("%d\n",qmax(x));
        }
    }
    return 0;
}

 

posted @ 2018-12-01 15:28  寒雨微凝  阅读(165)  评论(0编辑  收藏  举报