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

题目大意

有一棵\(n\)(\(n\leq10^5\))个节点的树,每个点有颜色\(c\),一开始所有颜色互不相同

要进行\(m\)(\(m\leq10^5\))次操作,每次操作是以下三种中的一种:

1.给出点\(x\),将点\(x\)到根路径上所有点的染成一种没出现过的颜色

2.给出点\(x\),\(y\),询问点\(x\)到\(y\)的简单路径上有多少种颜色

3.给出点\(x\),询问点\(x\)的子树中到根路径上颜色种类最多的点

题解

先坑着

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 100010
#define maxm (maxn<<1)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define ls (u<<1)
#define rs (u<<1|1)
#define ls2 son[u][0]
#define rs2 son[u][1]
#define mi (l+r>>1)
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!=‘-‘)ch=getchar();
    if(ch==‘-‘)f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-‘0‘,ch=getchar();
    return x*f;
}
void write(int x)
{
    if(x==0){putchar(‘0‘),putchar(‘\n‘);return;}
    int f=0;char ch[20];
    if(x<0)putchar(‘-‘),x=-x;
    while(x)ch[++f]=x%10+‘0‘,x/=10;
    while(f)putchar(ch[f--]);
    putchar(‘\n‘);
    return;
}
int fir[maxn],nxt[maxm],v[maxm],now,n,q;
int siz[maxn],dfn[maxn],top[maxn],fth[maxn],wson[maxn],dep[maxn],cnt,tim,to[maxn],tr[maxn<<2],mk[maxn<<2];
int fa[maxn],son[maxn][2],rev[maxn],st[maxn],tp,tmpdep[maxn];
void ade(int u1,int v1){v[cnt]=v1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
void getson(int u)
{
    siz[u]=1;
    view(u,k)if(v[k]!=fth[u])
    {
        fa[v[k]]=fth[v[k]]=u,tmpdep[v[k]]=tmpdep[u]+1,dep[v[k]]=dep[u]+1,getson(v[k]),siz[u]+=siz[v[k]];
        if(siz[v[k]]>siz[wson[u]])wson[u]=v[k];
    }
}
void gettop(int u,int anc)
{
    dfn[u]=++tim,to[tim]=u,top[u]=anc;
    if(wson[u])gettop(wson[u],anc);
    view(u,k)if(v[k]!=fth[u]&&v[k]!=wson[u])gettop(v[k],v[k]);
}
void build(int u,int l,int r)
{
    if(l==r){tr[u]=dep[to[l]]+1;return;}
    build(ls,l,mi),build(rs,mi+1,r),tr[u]=max(tr[ls],tr[rs]);return;
}
void mark(int u,int k){tr[u]+=k,mk[u]+=k;}
void pd(int u){if(mk[u]){mark(ls,mk[u]),mark(rs,mk[u]),mk[u]=0;}}
void add(int u,int l,int r,int x,int y,int k)
{
    if(x<=l&&r<=y)return mark(u,k);
    pd(u);
    if(x<=mi)add(ls,l,mi,x,y,k);
    if(y>mi)add(rs,mi+1,r,x,y,k);
    tr[u]=max(tr[ls],tr[rs]);
    return;
}
int ask(int u,int l,int r,int x,int y)
{
    if(x<=l&&r<=y)return tr[u];
    pd(u);
    int res=0;
    if(x<=mi)res=ask(ls,l,mi,x,y);
    if(y>mi)res=max(res,ask(rs,mi+1,r,x,y));
    return res;
}
int getso(int u){return son[fa[u]][0]!=u;}
int nort(int u){return son[fa[u]][0]==u||son[fa[u]][1]==u;}
void rot(int u)
{
    int fu=fa[u],ffu=fa[fu],l=getso(u),fl=getso(fu),r=l^1,rson=son[u][r];
    if(nort(fu))son[ffu][fl]=u;son[fu][l]=rson,son[u][r]=fu,fa[rson]=fu,fa[u]=ffu,fa[fu]=u;
}
void splay(int u)
{
    while(nort(u)){int fu=fa[u];if(nort(fu))rot(getso(u)^getso(fu)?u:fu);rot(u);}
}
int rnxt(int u){u=rs2;while(u){if(!ls2)break;u=ls2;}return u;}
int sroot(int u){while(u&&ls2)u=ls2;return u;}
void acs(int u)
{
    for(int vv=0;u;vv=u,u=fa[u])
    {
        splay(u);
        int tmp=rnxt(u),tmp2=sroot(vv);
        rs2=vv;
        if(tmp){add(1,1,n,dfn[tmp],dfn[tmp]+siz[tmp]-1,1);}
        if(tmp2){add(1,1,n,dfn[tmp2],dfn[tmp2]+siz[tmp2]-1,-1);}
    }
}
int Lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(tmpdep[top[x]]<tmpdep[top[y]])swap(x,y);
        x=fth[top[x]];
    }
    return tmpdep[x]<tmpdep[y]?x:y;
}
int main()
{
    //freopen("paint1.in","r",stdin);
    n=read(),q=read();
    memset(fir,-1,sizeof(fir));
    rep(i,1,n-1){int x=read(),y=read();ade(x,y),ade(y,x);}
    getson(1),/*cout<<"ook"<<endl,*/gettop(1,1),build(1,1,n);
    while(q--)
    {
        int f=read();
        if(f==1){int x=read();acs(x);}
        else if(f==2)
        {
            int x=read(),y=read(),lca=Lca(x,y),ansx=ask(1,1,n,dfn[x],dfn[x]),ansy=ask(1,1,n,dfn[y],dfn[y]),ansl=ask(1,1,n,dfn[lca],dfn[lca]);
            write(ansx+ansy-2*ansl+1);
        }
        else
        {
            int x=read();
            write(ask(1,1,n,dfn[x],dfn[x]+siz[x]-1));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/xzyf/p/10275488.html

时间: 2024-11-07 06:25:18

并不对劲的[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(

luogu P3703 [SDOI2017]树点涂色

luogu 看到操作1,应该学过lct的都知道这个等价于access操作,所以可以考虑用lct维护,相同颜色的一条链就用lct上的一棵splay维护,每次操作1就\(access(x)\) 要回答操作2和操作3,都要求出某点到根的颜色段数.考虑\(access(x)\)过程中会改变一些点的颜色段数,当某条边变成虚边后,那么对应儿子子树内所有点的颜色数都加\(1\),当某条边变成实边后,对应儿子子树内所有点的颜色数都减\(1\),这个不理解可以手动模拟access.然后操作二答案为\(a_x+a_