[SDOI2011]染色

此题我就用刚刚学过的LCT解吧……

颓废了好几天终于学了一个数据结构,还不精通qwq……不看题解我还是挂啊……

废话不多说,讲题。

题目描述

输入输出格式

解:

既然用LCT做,那就分析一下思路。

题目中求颜色数,那就先考虑维护什么吧。

一个点,需要维护它的父亲,它的儿子,它本身的颜色,它左孩子的颜色,右孩子的颜色,翻转标记,覆盖标记以及它的区间的颜色数。

(好累啊qwq)

题目中提到了无向边,自然联想到Link操作。

一个LCT的影子出来了。

对于每次修改,写一个区间放覆盖标记的pushl函数。

对于询问,先将a到b的路径合并(split),这个过程中标记什么的自动下放,维护整体结构,以此保证复杂度。

接下来。直接输出b的num即可。

(每次讲的很简单写起来要累死qwq)

注意所有的标记下放,对于翻转标记,不仅翻转儿子,还要翻转颜色。

对于覆盖标记,全部下放一遍。

pushup会有些麻烦,注意好左右孩子颜色以及它的颜色段数量维护即可。

代码:

#include<cstdio>
#include<iostream>
using namespace std;
struct node{
    int ch[2],fa,lcol,rcol,col,rev,tag,num;
}tr[500000];
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')w=-1;
        ch=getchar();
    }while(ch>='0'&&ch<='9'){
        s=(s<<1)+(s<<3)+(ch^48);
        ch=getchar();
    }x=s*w;return;
}inline bool root(int x){
    int g=tr[x].fa;
    return !(tr[g].ch[1]==x||tr[g].ch[0]==x);
}inline void pushup(int x){
    int l=tr[x].ch[0],r=tr[x].ch[1];
    tr[x].lcol=l?tr[l].lcol:tr[x].col;
    tr[x].rcol=r?tr[r].rcol:tr[x].col;
    if(l&&r)tr[x].num=tr[l].num+tr[r].num+1-(tr[l].rcol==tr[x].col)-(tr[r].lcol==tr[x].col);
    else if(l)tr[x].num=tr[l].num+(tr[l].rcol!=tr[x].col);
    else if(r)tr[x].num=tr[r].num+(tr[r].lcol!=tr[x].col);
    else tr[x].num=1;
}inline void pushr(int x){
    if(!x)return;
    swap(tr[x].ch[0],tr[x].ch[1]);
    swap(tr[x].lcol,tr[x].rcol);
    tr[x].rev^=1;
}inline void pushl(int x,int y){
    tr[x].col=tr[x].lcol=tr[x].rcol=y;
    tr[x].num=1;tr[x].tag=y;
}inline void pushdown(int x){
    int l=tr[x].ch[0],r=tr[x].ch[1];
    if(tr[x].tag){
        pushl(l,tr[x].tag);pushl(r,tr[x].tag);
        tr[x].tag=0;
    }if(tr[x].rev){
        pushr(l);pushr(r);
        tr[x].rev=0;
    }
}inline void rotate(int x){
    int y=tr[x].fa,z=tr[y].fa,k=tr[y].ch[1]==x;
    if(!root(y))tr[z].ch[tr[z].ch[1]==y]=x;
    tr[x].fa=z;tr[y].ch[k]=tr[x].ch[k^1];
    if(tr[x].ch[k^1])tr[tr[x].ch[k^1]].fa=y;
    tr[y].fa=x;tr[x].ch[k^1]=y;pushup(y);pushup(x);
}inline void pushrt(int x){
    if(!root(x))pushrt(tr[x].fa);
    pushdown(x);
}inline void splay(int x){
    int y,z;
    pushrt(x);
    while(!root(x)){
        y=tr[x].fa,z=tr[y].fa;
        if(!root(y))(tr[y].ch[1]==x)^(tr[z].ch[1]==y)?rotate(x):rotate(y);
        rotate(x);
    }pushup(x);
}inline void access(int x){
    for(int y=0;x;y=x,x=tr[x].fa){
        splay(x);tr[x].ch[1]=y;pushup(x);
    }
}inline void makeroot(int x){
    access(x);splay(x);pushr(x);
}inline void link(int x,int y){
    makeroot(x);tr[x].fa=y;
}inline void split(int x,int y){
    makeroot(x);access(y);splay(y);
}int n,m,a,b,c;
char s[50];
int main(){
    read(n);read(m);
    for(int i=1;i<=n;++i){
        read(tr[i].col);tr[i].lcol=tr[i].rcol=tr[i].col;tr[i].num=1;
    }for(int i=1;i<n;++i){
        read(a);read(b);
        link(a,b);
    }for(int i=1;i<=m;++i){
        cin>>s;read(a);read(b);
        split(a,b);
        if(s[0]=='C'){
            read(c);pushl(b,c);
        }else printf("%d\n",tr[b].num);
    }return 0;
}

 

posted @ 2019-06-04 19:13  Refined_heart  阅读(218)  评论(0编辑  收藏  举报