bzoj2243-染色(动态树lct)

解析:增加三个变量lc(最左边的颜色),rc(最右边的颜色),sum(连续相同颜色区间段数)。然后就是区间合并的搞法。我就不详细解释了,估计你已经想到

如何做了。

代码

#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=100005;
int N,M,C[maxn];
struct lct
{
    lct *fa,*son[2];
    int rev,c,setc,lc,rc,sum;
};
struct LCT
{
    lct data[maxn];
    lct *null;
    void init(int Size=maxn-1) //初始化
    {
        null=data; //null指向首元素
        for(int i=0;i<=Size;i++)
        {
            data[i].son[0]=data[i].son[1]=data[i].fa=null;
            data[i].rev=0;
            data[i].c=data[i].lc=data[i].rc=C[i];
            data[i].setc=-1;
            data[i].sum=1;
        }
        null->c=null->lc=null->rc=-1;
        null->sum=0;
    }
    void push_rev(lct* x)
    {
        if(x==null) return;
        x->rev=!x->rev;
        swap(x->son[0],x->son[1]);
        swap(x->lc,x->rc);
    }
    void push_setc(lct* x,int setc)
    {
        if(x==null) return;
        x->c=setc;
        x->setc=setc;
        x->lc=setc;
        x->rc=setc;
        x->sum=1;
    }
    void pushdown(lct* x)
    {
        if(x->setc!=-1)
        {
            push_setc(x->son[0],x->setc);
            push_setc(x->son[1],x->setc);
            x->setc=-1;
        }
        if(x->rev)
        {
            push_rev(x->son[0]);
            push_rev(x->son[1]);
            x->rev=0;
        }
    }
    void pushup(lct* x)
    {
        if(x==null) return;
        x->sum=1;
        if(x->son[0]!=null)
        {
            x->sum+=x->son[0]->sum;
            if(x->son[0]->rc==x->c) x->sum--;
        }
        if(x->son[1]!=null)
        {
            x->sum+=x->son[1]->sum;
            if(x->son[1]->lc==x->c) x->sum--;
        }
        x->lc=x->c;
        if(x->son[0]!=null) x->lc=x->son[0]->lc;
        x->rc=x->c;
        if(x->son[1]!=null) x->rc=x->son[1]->rc;
    }
    bool Same(lct* x,lct* &y) //判断x和x的父亲是否在同一树里
    {
        return (y=x->fa)!=null&&(y->son[0]==x||y->son[1]==x);
    }
    void Rotate(lct* x,int d) //翻转
    {
        lct* y=x->fa; //x的父亲
        y->son[d^1]=x->son[d];
        if(x->son[d]!=null) x->son[d]->fa=y; //x的子节点的父亲指向y
        x->fa=y->fa;  //连接
        if(y->fa->son[0]==y) x->fa->son[0]=x;
        else if(y->fa->son[1]==y) x->fa->son[1]=x;
        x->son[d]=y;
        y->fa=x;
    }
    void Splay(lct* x)
    {
        pushdown(x); //清除标记
        lct* y;
        while(Same(x,y)) //没有到树的最顶点
        {
            pushdown(y);
            pushdown(x);
            Rotate(x,y->son[0]==x); //翻转
            pushup(y);
            pushup(x);
        }
    }
    lct* Access(lct* u)  //打通路径,返回的是根
    {
        lct *v=null;
        for(;u!=null;u=u->fa)
        {
            Splay(u);
            u->son[1]=v;
            pushup(v=u);
        }
        return v;
    }
    lct* GetRoot(lct* x) //得到根
    {
        for(x=Access(x);pushdown(x),x->son[0]!=null;x=x->son[0]) pushup(x);
        return x;
    }
    void MakeRoot(lct* x) //使x成为根
    {
        Access(x);
        Splay(x);
        push_rev(x);
    }
    void Link(lct* x,lct* y) //连接两个点
    {
        MakeRoot(x);
        x->fa=y;
        Access(x);
    }
    void Cut(lct* x,lct* y) //断开两个点
    {
        MakeRoot(x);
        Access(y);
        Splay(y);
        y->son[0]->fa=null;
        y->son[0]=null;
    }
    void SetC(lct* x,lct* y,int setc)
    {
        MakeRoot(x);
        push_setc(Access(y),setc);
    }
    int Query(lct* x,lct* y)
    {
        MakeRoot(x);
        Access(y);
        Splay(y);
        return y->sum;
    }
}A;
int main()
{
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N;i++) scanf("%d",&C[i]);
    A.init(N);
    int x,y;
    for(int i=1;i<N;i++)
    {
        scanf("%d%d",&x,&y);
        A.Link(A.data+x,A.data+y);
    }
    char op[3];
    int c;
    while(M--)
    {
        scanf("%s%d%d",op,&x,&y);
        if(op[0]==‘C‘) scanf("%d",&c);
        if(op[0]==‘C‘) A.SetC(A.data+x,A.data+y,c);
        else printf("%d\n",A.Query(A.data+x,A.data+y));
    }
    return 0;
}

时间: 2024-10-03 20:42:33

bzoj2243-染色(动态树lct)的相关文章

bzoj2243 [SDOI2011]染色 动态树

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 110000 int pre[N],ch[N][2]; int e[N],ne[N*2],v[N*2]; int nn,m; int col[N]; int lc[N],sm[N],rc[N],num[N]; int rt[N],n; int qu[N

hdu 5398 动态树LCT

GCD Tree Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 415    Accepted Submission(s): 172 Problem Description Teacher Mai has a graph with n vertices numbered from 1 to n. For every edge(u,v),

hdu 5002 (动态树lct)

Tree Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 920    Accepted Submission(s): 388 Problem Description You are given a tree with N nodes which are numbered by integers 1..N. Each node is a

bzoj2049-洞穴勘测(动态树lct模板题)

Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为这两个洞穴之间的一条路径.洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结果,123号洞穴和127号洞穴之间有时会出现一条通

动态树LCT小结

最开始看动态树不知道找了多少资料,总感觉不能完全理解.但其实理解了就是那么一回事...动态树在某种意思上来说跟树链剖分很相似,都是为了解决序列问题,树链剖分由于树的形态是不变的,所以可以通过预处理节点间的关系,将树转化成连续的区间,再加以其它的数据结构,便能以较快的速度处理序列的修改和查询. 而动态树的问题,是包括了树的合并和拆分操作.这个时候,通过预处理实现的静态树的序列算法不能满足我们的要求,于是我们需要一颗‘动态’的树,能在O(logN)的时间复杂度,处理所有操作. Splay实现的Lin

[模板] 动态树/LCT

简介 LCT是一种数据结构, 可以维护树的动态加边, 删边, 维护链上信息(满足结合律), 单次操作时间复杂度 \(O(\log n)\).(不会证) 思想类似树链剖分, 因为splay可以换根, 用splay维护重链, splay的中序遍历即为链按深度从小到大遍历的结果. 注意区分splay和整棵树的区别, splay根和树根的区别. \(Access(p)\) 操作指的是将p与根放在同一棵splay中. \(MakeRoot(p)\) 操作指的是将p变为它所在树(而不是splay)的根. 由

[SDOI2011][BZOJ2243] 染色|线段树|树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3583  Solved: 1362[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

HDU 5002 Tree(动态树LCT)(2014 ACM/ICPC Asia Regional Anshan Online)

Problem Description You are given a tree with N nodes which are numbered by integers 1..N. Each node is associated with an integer as the weight. Your task is to deal with M operations of 4 types: 1.Delete an edge (x, y) from the tree, and then add a

动态树 LCT

bzoj2049 洞穴探测 题目大意:lct(link,cut,判联通). #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define maxnode 10005 using namespace std; struct lct{ int fa[maxnode],ch[maxnode][2],rev[maxnode],zh[maxnode]; void in