luogu P3703 [SDOI2017]树点涂色

luogu

看到操作1,应该学过lct的都知道这个等价于access操作,所以可以考虑用lct维护,相同颜色的一条链就用lct上的一棵splay维护,每次操作1就\(access(x)\)

要回答操作2和操作3,都要求出某点到根的颜色段数.考虑\(access(x)\)过程中会改变一些点的颜色段数,当某条边变成虚边后,那么对应儿子子树内所有点的颜色数都加\(1\),当某条边变成实边后,对应儿子子树内所有点的颜色数都减\(1\),这个不理解可以手动模拟access.然后操作二答案为\(a_x+a_y-2*a_{lca}+1\),就是两条从lca往下的链答案+lca的贡献.操作三要询问子树,但是一个点子树在\(dfs\)序上是连续区间,所以线段树维护每个点以及子树内答案即可

//补档
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define ldb long double

using namespace std;
const int N=100000+10;
il LL rd()
{
    LL x=0,w=1;char ch;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
il void add(int x,int y)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
    ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int n,m,ff[N],de[N],sz[N],hson[N],top[N],dfn[N],id[N],tt;
int fa[N],ch[N][2];
void dfs1(int x)
{
    sz[x]=1;
    for(int i=hd[x];i;i=nt[i])
    {
        int y=to[i];
        if(y==ff[x]) continue;
        ff[y]=fa[y]=x,de[y]=de[x]+1,dfs1(y),sz[x]+=sz[y];
        if(sz[hson[x]]<sz[y]) hson[x]=y;
    }
}
void dfs2(int x,int ntp)
{
    dfn[x]=++tt,id[tt]=x,top[x]=ntp;
    if(hson[x]) dfs2(hson[x],ntp);
    for(int i=hd[x];i;i=nt[i])
    {
        int y=to[i];
        if(y==ff[x]||y==hson[x]) continue;
        dfs2(y,y);
    }
}
il int glca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(de[top[x]]<de[top[y]]) swap(x,y);
        x=ff[top[x]];
    }
    return de[x]<de[y]?x:y;
}
int ma[N<<2],lz[N<<2];
#define lc (o<<1)
#define rc ((o<<1)|1)
#define mid ((l+r)>>1)
il void psup(int o){ma[o]=max(ma[lc],ma[rc]);}
il void upd(int o,int x){ma[o]+=x,lz[o]+=x;}
il void psdn(int o)
{
    if(lz[o]) upd(lc,lz[o]),upd(rc,lz[o]),lz[o]=0;
}
void bui(int o,int l,int r)
{
    if(l==r) {ma[o]=de[id[l]];return;}
    bui(lc,l,mid),bui(rc,mid+1,r);
    psup(o);
}
void modif(int o,int l,int r,int ll,int rr,int x)
{
    if(ll<=l&&r<=rr)
    {
        upd(o,x);
        return;
    }
    psdn(o);
    if(ll<=mid) modif(lc,l,mid,ll,rr,x);
    if(rr>mid) modif(rc,mid+1,r,ll,rr,x);
    psup(o);
}
int quer(int o,int l,int r,int ll,int rr)
{
    if(ll<=l&&r<=rr) return ma[o];
    int an=0;
    psdn(o);
    if(ll<=mid) an=max(an,quer(lc,l,mid,ll,rr));
    if(rr>mid) an=max(an,quer(rc,mid+1,r,ll,rr));
    psup(o);
    return an;
}
il bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
il void rot(int x)
{
    int y=fa[x],z=fa[y],yy=ch[y][1]==x,w=ch[x][!yy];
    if(nrt(y)) ch[z][ch[z][1]==y]=x;
    ch[y][yy]=w,ch[x][!yy]=y;
    if(w) fa[w]=y;
    fa[y]=x,fa[x]=z;
}
il void spl(int x)
{
    int y,z;
    while(nrt(x))
    {
        y=fa[x],z=fa[y];
        if(nrt(y)) ((ch[y][1]==x)^(ch[z][1]==y))?rot(x):rot(y);
        rot(x);
    }
}
il int findrt(int x)
{
    while(ch[x][0]) x=ch[x][0];
    return x;
}
il void acs(int x)
{
    for(int y=0,z;x;y=x,x=fa[x])
    {
        spl(x);
        if(ch[x][1]) z=findrt(ch[x][1]),modif(1,1,n,dfn[z],dfn[z]+sz[z]-1,1);
        if(y) z=findrt(y),modif(1,1,n,dfn[z],dfn[z]+sz[z]-1,-1);
        ch[x][1]=y;
    }
}

int main()
{
    n=rd(),m=rd();
    for(int i=1;i<n;++i) add(rd(),rd());
    de[1]=1,dfs1(1),dfs2(1,1),bui(1,1,n);
    while(m--)
    {
        int op=rd();
        if(op==1) acs(rd());
        else if(op==2)
        {
            int x=rd(),y=rd(),lca=glca(x,y);
            printf("%d\n",quer(1,1,n,dfn[x],dfn[x])+quer(1,1,n,dfn[y],dfn[y])-(quer(1,1,n,dfn[lca],dfn[lca])<<1)+1);
        }
        else
        {
            int x=rd();
            printf("%d\n",quer(1,1,n,dfn[x],dfn[x]+sz[x]-1));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/smyjr/p/11493004.html

时间: 2024-11-06 23:17:47

luogu P3703 [SDOI2017]树点涂色的相关文章

[BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)

4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 692  Solved: 408[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这几种操作: 1 x: 把点x到根节点的路径上所有的点染上一种

[BZOJ]4817: [Sdoi2017]树点涂色

Time Limit: 10 Sec  Memory Limit: 128 MB Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这几种操作: 1 x: 把点x到根节点的路径上所有的点染上一种没有用过的新颜色. 2 x y: 求x到y的路径的权值. 3 x y: 在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大

4817 [Sdoi2017]树点涂色

题目描述 Bob 有一棵 n 个点的有根树,其中 1 号点是根节点.Bob 在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob可能会进行这几种操作: 1 x 表示把点 x 到根节点的路径上所有的点染上一种没有用过的新颜色. 2 x y 求 x 到 y 的路径的权值. 3 x 在以 x 为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值. Bob一共会进行 m 次操作 输入格式 第一行两个数 n,m.

BZOJ4817 [Sdoi2017]树点涂色

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目链接:BZOJ4817 正解:$LCT$+线段树 解题报告: 考虑操作$1$很类似$LCT$中的$access$操作,我们可以借助$LCT$的复杂度证明,来保证用$LCT$的实现方式来完成本题的操作复杂度的正确性. 我们维护每个点到根的权值,用线段树维

bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】

非常妙的一道题. 首先对于操作一"把点x到根节点的路径上所有的点染上一种没有用过的新颜色",长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT中的重边的话,那么询问二就相当于问路径上的虚边有多少. 然后第二.三个操作是可以用树剖在线段树上维护的. 设每个点的权值\( val \)为这个点到根的路径上颜色个数,也就是虚边个数.那么考虑access操作的影响,对于他断开的重边,所在子树加一,对于他连上的重边,所在子树减一.直接在access过程中处理即

BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)

题目链接 1.2裸树剖,但是3.每个点的答案val很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边,相同颜色点用实边相连.一条边由实边变为虚边时,深度大的点所在子树所有点val+1(Access()中原先x的右儿子答案+1,因为x颜色变了): 由虚边变为实边时,深度大的点所在子树所有点val-1(fa[x]颜色与x相同导致fa[x]的贡献没了).(其实是因为 实链数量(贡献)就等于虚边数量+1?无所谓了) 于是2.就是val

【bzoj4817】[Sdoi2017]树点涂色&amp;&amp;bzoj3779-重组病毒

题解: 两道几乎差不多的题(所以说当年sdoi考了道原题) 都是将树上一段改为新颜色询问颜色数目 可以把改成新颜色这个操作看成access操作 然后通过线段树+dfs序来维护 另外换根了为什么还可以用dfs序来维护 我们观察一下会发现 1.当根在x当中,就是除了根那边那块 2.不在的话就是原先的子树 原文地址:https://www.cnblogs.com/yinwuxiao/p/9272857.html

SDOI2017 树点涂色

题目描述 题解: SDOI SD题. LCT维护线段树, 线段树维护dfs序. 由于每次修改只是从根到x,我们可以将它理解为LCT的access操作. 然后轻重链信息发生变化时,在线段树上改一下就好了. LCTaccess板子敲错导致自己做自己爷爷. 代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 inline int rd(

并不对劲的[SDOI2017]树点涂色

题目大意 有一棵\(n\)(\(n\leq10^5\))个节点的树,每个点有颜色\(c\),一开始所有颜色互不相同 要进行\(m\)(\(m\leq10^5\))次操作,每次操作是以下三种中的一种: 1.给出点\(x\),将点\(x\)到根路径上所有点的染成一种没出现过的颜色 2.给出点\(x\),\(y\),询问点\(x\)到\(y\)的简单路径上有多少种颜色 3.给出点\(x\),询问点\(x\)的子树中到根路径上颜色种类最多的点 题解 先坑着 代码 #include<algorithm>