码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ4817][SDOI2017]树点涂色

时间:2018-01-23 13:04:29      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:bool   top   root   就是   ==   int   gpo   print   注意   

BZOJ
Luogu

sol

这个题只要你想清楚了就变成码农题了。
你会发现操作1神似\(LCT\)中的\(access\)
考虑在某一次1操作中,会有若干组父子关系,有的是父子从同色变成了异色,有的是从异色变成了同色。如果我们就把同色的点放在一棵splay里面,那操作就直接对应\(access\)操作了。
我们考虑维护这个东西:每个点到根的路径权值\(val_i\)
如果一对父子的颜色从同色变成异色,那么原树中以那个儿子为根的子树的每个点的权值都会加一;反之,若从异色变同色,那么就会全部减一。而对应到\(access\)中,由同变异的刚好是原实儿子,由异变同的刚好是新实儿子。
子树转化成区间,然后就是经典线段树操作。
对于操作2,答案是\(val_x+val_y-2*val_{lca(u,v)}+1\)
所以你需要写LCA+LCT+支持区间加和区间查最大值的线段树

注意:在\(access\)中,打标记的位置是链顶
所以要在splay中暴跳一下左儿子找到最左边那个点

code

LCA沉迷树链剖分无法自拔
线段树可以标记永久化
LCT只要写\(access\),连\(rev\)都不用打

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100005;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
struct edge{int to,next;}a[N<<1];
int n,m,head[N],cnt,pa[N],dep[N],sz[N],son[N],top[N],dfn[N],low[N];
void dfs1(int u,int f)
{
    pa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
    for (int e=head[u];e;e=a[e].next)
    {
        int v=a[e].to;if (v==f) continue;
        dfs1(v,u);
        sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int up)
{
    top[u]=up;dfn[u]=++cnt;
    if (son[u]) dfs2(son[u],up);
    for (int e=head[u];e;e=a[e].next)
        if (a[e].to!=pa[u]&&a[e].to!=son[u])
            dfs2(a[e].to,a[e].to);
    low[u]=cnt;
}
int getlca(int u,int v)
{
    while (top[u]^top[v])
    {
        if (dep[top[u]]<dep[top[v]]) swap(u,v);
        u=pa[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
int tag[N<<2],mx[N<<2];
void Modify(int x,int l,int r,int ql,int qr,int v)
{
    if (l>=ql&&r<=qr)
    {
        tag[x]+=v;mx[x]+=v;
        return;
    }
    int mid=l+r>>1;
    if (ql<=mid) Modify(x<<1,l,mid,ql,qr,v);
    if (qr>mid) Modify(x<<1|1,mid+1,r,ql,qr,v);
    mx[x]=max(mx[x<<1],mx[x<<1|1])+tag[x];
}
int Query(int x,int l,int r,int ql,int qr)
{
    if (l>=ql&&r<=qr) return mx[x];
    int mid=l+r>>1,s=-1e9;
    if (ql<=mid) s=max(s,Query(x<<1,l,mid,ql,qr));
    if (qr>mid) s=max(s,Query(x<<1|1,mid+1,r,ql,qr));
    return s+tag[x];
}
int fa[N],ls[N],rs[N];
bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void R_rotate(int x)
{
    int y=fa[x],z=fa[y];
    ls[y]=rs[x];
    if (rs[x]) fa[rs[x]]=y;
    fa[x]=z;
    if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x;
    rs[x]=y;fa[y]=x;
}
void L_rotate(int x)
{
    int y=fa[x],z=fa[y];
    rs[y]=ls[x];
    if (ls[x]) fa[ls[x]]=y;
    fa[x]=z;
    if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x;
    ls[x]=y;fa[y]=x;
}
void splay(int x)
{
    while (!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if (isroot(y))
            if (x==ls[y]) R_rotate(x);
            else L_rotate(x);
        else
            if (y==ls[z])
                if (x==ls[y]) R_rotate(y),R_rotate(x);
                else L_rotate(x),R_rotate(x);
            else
                if (x==ls[y]) R_rotate(x),L_rotate(x);
                else L_rotate(y),L_rotate(x);
    }
}
int getf(int x){while(ls[x])x=ls[x];return x;}
void access(int x)
{
    int gg;
    for (int y=0;x;y=x,x=fa[x])
    {
        splay(x);
        if (rs[x]) gg=getf(rs[x]),Modify(1,1,n,dfn[gg],low[gg],1);
        if (y) gg=getf(y),Modify(1,1,n,dfn[gg],low[gg],-1);
        rs[x]=y;
    }
}
int main()
{
    n=gi();m=gi();
    for (int i=1,u,v;i<n;i++)
    {
        u=gi();v=gi();
        a[++cnt]=(edge){v,head[u]};head[u]=cnt;
        a[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    dfs1(1,0);cnt=0;dfs2(1,1);
    for (int i=1;i<=n;i++) fa[i]=pa[i],Modify(1,1,n,dfn[i],low[i],1);
    while (m--)
    {
        int opt=gi(),x=gi(),y,gg;
        if (opt==1) access(x);
        if (opt==2)
        {
            y=gi();
            gg=getlca(x,y);
            printf("%d\n",Query(1,1,n,dfn[x],dfn[x])+Query(1,1,n,dfn[y],dfn[y])-2*Query(1,1,n,dfn[gg],dfn[gg])+1);
        }
        if (opt==3) printf("%d\n",Query(1,1,n,dfn[x],low[x]));
    }
    return 0;
}

[BZOJ4817][SDOI2017]树点涂色

标签:bool   top   root   就是   ==   int   gpo   print   注意   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8334926.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!