BZOJ - 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 10456  Solved: 4013
[Submit][Status][Discuss]

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

 

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

HINT

 

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

 

Source

 

思路:树链剖分+线段树维护颜色,我们要确定每段颜色的时候,需要记录左右儿子。最后查询u->v的时候要注意,不在一条链上,我们需要判断合并时候的颜色是否相同。

 

大概就是情况,合并的时候左边的右儿子和右边的做儿子。 

#include<bits/stdc++.h>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define P pair<int,int>
#define INF 1e18
#define mod 998244353
using namespace std;
const int maxn = 100005;
int head[maxn],Next[maxn*20],To[maxn*20],pos[maxn],tot,cnt,n;
int son[maxn],fa[maxn],size[maxn],top[maxn],id[maxn],deep[maxn];
int lazy[maxn<<2],num[maxn<<2],ls[maxn<<2],rs[maxn<<2],a[maxn];
void add(int u,int v)
{
    Next[++cnt]=head[u];
    head[u]=cnt;
    To[cnt]=v;
}
void dfs1(int u,int f,int dep)
{
    fa[u]=f;
    size[u]=1;
    deep[u]=dep+1;
    int mx=0;
    for(int i=head[u]; i!=-1; i=Next[i])
    {
        int v=To[i];
        if(v==f) continue;
        dfs1(v,u,dep+1);
        size[u]+=size[v];
        if(size[v]>mx) mx=size[v],son[u]=v;
    }
    size[u]++;
}
void dfs2(int u,int tp)
{
    id[u]=++tot;
    pos[tot]=u;
    top[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(int i=head[u]; i!=-1; i=Next[i])
    {
        int v=To[i];
        if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
    }
}
void push_up(int rt)
{
    ls[rt]=ls[rt<<1];
    rs[rt]=rs[rt<<1|1];
    num[rt]=num[rt<<1]+num[rt<<1|1]-(ls[rt<<1|1]==rs[rt<<1]);
 
}
void push_down(int rt)
{
    if(lazy[rt]!=-1)
    {
        num[rt<<1]=num[rt<<1|1]=1;
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        ls[rt<<1]=rs[rt<<1]=lazy[rt];
        ls[rt<<1|1]=rs[rt<<1|1]=lazy[rt];
        lazy[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
    lazy[rt]=-1;
    if(l==r)
    {
        ls[rt]=rs[rt]=a[pos[l]];
        num[rt]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}
void updata(int l,int r,int rt,int L,int R,ll c)
{
    if(L<=l&&r<=R)
    {
        lazy[rt]=ls[rt]=rs[rt]=c;
        num[rt]=1;
        return ;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(L<=m) updata(lson,L,R,c);
    if(R>m) updata(rson,L,R,c);
    push_up(rt);
}
void change(int u,int v,ll c)
{
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]]) swap(u,v);
        updata(1,n,1,id[top[u]],id[u],c);
        u=fa[top[u]];
    }
    if(deep[u]>deep[v]) swap(u,v);
    updata(1,n,1,id[u],id[v],c);
}
int query(int l,int r,int rt,int L,int R)
{
    if(L<=l&&r<=R)
    {
        return num[rt];
    }
    push_down(rt);
    ll ans=0;
    int m=(l+r)>>1;
    if(L<=m)  ans+=query(lson,L,R);
    if(R>m)  ans+=query(rson,L,R);
    if(L<=m&&R>m&&rs[rt<<1]==ls[rt<<1|1]) ans--;
    return ans;
}
int Qcolor(int l,int r,int rt,int pos)
{
    if(l==r)
        return ls[rt];
    push_down(rt);
    int m=(l+r)>>1;
    if(pos<=m) return Qcolor(lson,pos);
    else return Qcolor(rson,pos);
}
int Query(int u,int v)
{
    int ans=0;
    while(top[u]!=top[v])
    {
        if(deep[top[u]]<deep[top[v]]) swap(u,v);
        ans+=query(1,n,1,id[top[u]],id[u])-(Qcolor(1,n,1,id[top[u]])==Qcolor(1,n,1,id[fa[top[u]]]));
        u=fa[top[u]];
    }
    if(deep[u]>deep[v]) swap(u,v);
    return ans+query(1,n,1,id[u],id[v]);
}
int main()
{
    int m,u,v;
    memset(head,-1,sizeof(head));
    scanf("%d %d",&n,&m);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]);
    for(int i=1; i<n; i++)
    {
        scanf("%d %d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(1,-1,0);
    dfs2(1,1);
    build(1,n,1);
    while(m--)
    {
        char op[5];
        int a,b,c;
        scanf("%s%d%d",op,&a,&b);
        if(op[0]=='Q')
        {
            printf("%d\n",Query(a,b));
        }
        else
        {
            scanf("%d",&c);
            change(a,b,c);
        }
    }
 
}
View Code

 

 

 


PS:摸鱼怪的博客分享,欢迎感谢各路大牛的指点~
posted @ 2018-08-21 21:07  MengX  阅读(206)  评论(0编辑  收藏  举报

梦想不是空想