首页 > 代码库 > [codevs1566]染色

[codevs1566]染色

 

题目描述 Description

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

输入描述 Input Description

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面n-1行每行包含两个整数 和 ,表示xy之间有一条无向边。

下面m行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

输出描述 Output Description
 对于每个询问操作,输出一行答案。
样例输入 Sample Input
 

6 5

2 2 1 2 1 1

1 2

1 3

2 4

2 5

2 6

Q 3 5

C 2 1 1

Q 3 5

C 5 1 2

Q 3 5


样例输出 Sample Output
 

3

1

2

数据范围及提示 Data Size & Hint
 对于100%的数据1≤n≤10^5,1≤m≤10^5,1≤c≤10^9;

很明显是一道树链剖分的题,所以我们只需要考虑线性时候该怎么搞了。

用线段树是肯定的。对于每一个节点o,维护该区间内颜色块数量是肯定的,用cnum[o]来表示。但是发现不能强行合并,因为相邻部分有可能颜色相同,算成一块。所以我们再需要维护两个信息L[o]与R[o]分别记录区间o最左端的颜色以及最右边颜色就可以了。在pushup过程中需要判断如果r[lo]==l[ro],cnum[o]--;这样的话线性做法就可以了。

写好线段树之后,默一份树链剖分代码上去,套一个线段树,结果发现连样例都过不了!手画一下样例,发现在树链上进行操作时进行了若干次query,这些query中的相邻部分有可能颜色相同,怎么办呢,不要慌,我们再写一个名叫special的函数,专门来计算每一条重链上最上段点的颜色,在合并的时候特判一下就好了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c==-)f=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-0;c=getchar();}
    return x*f;
}
const int maxn=100010;
int n,m,ce=-1,es,a,b,c,first[maxn],size[maxn],fa[maxn],deep[maxn],w[maxn],id[maxn],bl[maxn];
char tp;
int cnum[maxn<<2],L[maxn<<2],R[maxn<<2],tag[maxn<<2],col[maxn];
struct Edge
{
    int u,v,next;
    Edge() {}
    Edge(int _1,int _2,int _3) : u(_1),v(_2),next(_3) {}
}e[maxn<<1];
void addEdge(int a,int b)
{
    e[++ce]=Edge(a,b,first[a]);first[a]=ce;
    e[++ce]=Edge(b,a,first[b]);first[b]=ce;
}
void dfs(int now,int pa)
{
    size[now]=1;
    for(int i=first[now];i!=-1;i=e[i].next)
        if(e[i].v!=pa)
        {
            fa[e[i].v]=now;deep[e[i].v]=deep[now]+1;
            dfs(e[i].v,now);
            size[now]+=size[e[i].v];
        }
}
void divide(int now,int chain)
{
    id[now]=++es;bl[now]=chain;
    int maxs=0;
    for(int i=first[now];i!=-1;i=e[i].next)
        if(fa[now]!=e[i].v && size[e[i].v]>size[maxs])maxs=e[i].v;
    if(!maxs)return;
    divide(maxs,chain);
    for(int i=first[now];i!=-1;i=e[i].next)
        if(fa[now]!=e[i].v && e[i].v!=maxs)divide(e[i].v,e[i].v);
}
void pushdown(int l,int r,int o)
{
    if(tag[o]==-1 || l==r)return;
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
    tag[lo]=tag[ro]=tag[o];
    cnum[lo]=cnum[ro]=1;
    L[lo]=R[lo]=L[ro]=R[ro]=L[o];
    tag[o]=-1;
}
void pushup(int l,int r,int o)
{
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
    L[o]=L[lo];R[o]=R[ro]; 
    cnum[o]=cnum[lo]+cnum[ro];
    if(R[lo]==L[ro])cnum[o]--;
}
void build(int l,int r,int o)
{
    if(l==r)
    {
        cnum[o]=1;tag[o]=-1;
        L[o]=R[o]=col[l];
        return;
    }
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
    build(l,mid,lo);build(mid+1,r,ro); 
    pushup(l,r,o);tag[o]=-1;
}
void update(int l,int r,int o,int a,int b,int c)
{
    if(l==a && r==b)
    {
        tag[o]=c;cnum[o]=1;
        L[o]=R[o]=c;
        return;
    }
    pushdown(l,r,o);
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
    if(b<=mid)update(l,mid,lo,a,b,c);
    else if(a>mid)update(mid+1,r,ro,a,b,c);
    else
    {
        update(l,mid,lo,a,mid,c);
        update(mid+1,r,ro,mid+1,b,c);
    }
    pushup(l,r,o);
}
int query(int l,int r,int o,int a,int b)
{
    if(l==a && r==b)return cnum[o];
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
    pushdown(l,r,o); 
    if(a>mid)return query(mid+1,r,ro,a,b);
    else if(b<=mid)return query(l,mid,lo,a,b);
    else
    {
        int ans=query(l,mid,lo,a,mid)+query(mid+1,r,ro,mid+1,b);
        return R[lo]==L[ro] ? ans-1 : ans;
    }    
}
int special(int l,int r,int o,int a)
{
    if(l==r)return L[o];
    pushdown(l,r,o);
    int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
    if(a<=mid)return special(l,mid,lo,a);
    else return special(mid+1,r,ro,a);
}
void paint(int a,int b,int c)
{
    while(bl[a]!=bl[b])
    {
        if(deep[bl[a]]<deep[bl[b]])swap(a,b);
        update(1,n,1,id[bl[a]],id[a],c);
        a=fa[bl[a]];
    }
    if(id[a]>id[b])swap(a,b);
    update(1,n,1,id[a],id[b],c);
}
int Query(int a,int b)
{
    int sum=0;
    while(bl[a]!=bl[b])
    {
        if(deep[bl[a]]<deep[bl[b]])swap(a,b);
        sum+=query(1,n,1,id[bl[a]],id[a]);
        if(special(1,n,1,id[bl[a]])==special(1,n,1,id[fa[bl[a]]]))sum--;
        a=fa[bl[a]];
    }
    if(id[a]>id[b])swap(a,b);
    sum+=query(1,n,1,id[a],id[b]);
    return sum;
}
int main()
{
    mem(first,-1);
    n=read();m=read();
    for(int i=1;i<=n;i++)w[i]=read();
    for(int i=1;i<n;i++)a=read(),b=read(),addEdge(a,b);
    dfs(1,1);divide(1,1);
    for(int i=1;i<=n;i++)col[id[i]]=w[i];
    build(1,n,1);
    while(m--)
    {
        cin>>tp;a=read();b=read();
        if(tp==C)c=read(),paint(a,b,c);
        else printf("%d\n",Query(a,b));
    }
    return 0;
}

 

[codevs1566]染色