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


2243: [SDOI2011] 染色

  Time Limit: 20 Sec
  Memory Limit: 512 MB

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 1###

  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 1###

  3
  1
  2

HINT###

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

题目地址: BZOJ 2243: [SDOI2011]染色

题解:

     
  此题的关键是线段树记录的信息是什么
  线段树上记三个量:
  该段颜色段数,左端点颜色,右端点颜色
  在合并的时候段点颜色要特别小心仔细
  写法技巧和细节也很重要
  其余树链剖分
www.cnblogs.com/AGFghy/


AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int n,m,u,v,x,y,c,num,cnt;
int point[N<<1],next[N<<1],head[N];
int fa[N],dep[N],size[N],son[N],id[N],top[N];
int a[N],fc[N];
char pd[5];
struct node
{
    int lc,rc,v,lazy;
}tree[N<<2]; 
void add(int u,int v)
{
    point[++num]=v;
    next[num]=head[u];
    head[u]=num;
}
void dfs1(int now,int pre)
{
    fa[now]=pre;
    dep[now]=dep[pre]+1;
    size[now]=1;
    for (int i=head[now]; i; i=next[i])
    {
        int v=point[i];
        if (v==pre) continue;
        dfs1(v,now);
        size[now]+=size[v];
        if (size[v]>size[son[now]]) son[now]=v;
    }
}
void dfs2(int now,int topf)
{
    top[now]=topf;
    id[now]=++cnt;
    a[cnt]=fc[now]+1;
    if (!son[now]) return;
    dfs2(son[now],topf);
    for (int i=head[now]; i; i=next[i])
    {
        int v=point[i];
        if (v==fa[now] || v==son[now]) continue;
        dfs2(v,v);
    }
}
void pushup(int p)
{
    tree[p].lc=tree[p<<1].lc;
    tree[p].rc=tree[(p<<1)+1].rc;
    tree[p].v=tree[p<<1].v+tree[(p<<1)+1].v-(tree[p<<1].rc==tree[(p<<1)+1].lc);
}
void pushdown(int p)
{
    if (tree[p].lazy)
    {
        tree[p<<1].lc=tree[p<<1].rc=tree[p<<1].lazy=tree[p].lazy; tree[p<<1].v=1;
        tree[(p<<1)+1].lc=tree[(p<<1)+1].rc=tree[(p<<1)+1].lazy=tree[p].lazy; tree[(p<<1)+1].v=1;
        tree[p].lazy=0;
    }
}
void build(int l,int r,int p)
{
    if (l==r)
    {
        tree[p].lc=tree[p].rc=a[l];
        tree[p].v=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,(p<<1)+1);
    pushup(p);
}
void update(int l,int r,int p,int s,int t,int c)
{
    if (l==s && r==t)
    {
        tree[p].lc=tree[p].rc=tree[p].lazy=c;
        tree[p].v=1;
        return;
    }
    pushdown(p);
    int mid=(l+r)>>1;
    if (t<=mid) update(l,mid,p<<1,s,t,c);
    else if (s>mid) update(mid+1,r,(p<<1)+1,s,t,c);
    else
    {
        update(l,mid,p<<1,s,mid,c);
        update(mid+1,r,(p<<1)+1,mid+1,t,c);
    }
    pushup(p);
}
node query(int l,int r,int p,int s,int t)
{
    if (l==s && r==t) return tree[p];
    pushdown(p);
    int mid=(l+r)>>1;
    if (t<=mid) return query(l,mid,p<<1,s,t);
    else if (s>mid) return query(mid+1,r,(p<<1)+1,s,t);
    else
    {
        node res,s1,s2;
        s1=query(l,mid,p<<1,s,mid);   s2=query(mid+1,r,(p<<1)+1,mid+1,t);
        res.lc=s1.lc; res.rc=s2.rc;
        res.v=s1.v+s2.v-(s1.rc==s2.lc);
        return res;
    }
}
void cover(int x,int y,int c)
{
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,n,1,id[top[x]],id[x],c);
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    update(1,n,1,id[x],id[y],c);
}
int seg(int x,int y)
{
    int xc=-1,yc=-1,ans=0;
    node now;
    while (top[x]!=top[y])
    {
         
        if (dep[top[x]]<dep[top[y]]) swap(x,y),swap(xc,yc);
        now=query(1,n,1,id[top[x]],id[x]);
        ans+=now.v-(now.rc==xc);
        xc=now.lc; x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y),swap(xc,yc);
    now=query(1,n,1,id[x],id[y]);
    ans+=now.v-(now.lc==xc)-(now.rc==yc);
    return ans; 
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++)
        scanf("%d",&fc[i]);
    for (int i=1; i<n; i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v); add(v,u);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,n,1);
    while (m--)
    {
        scanf("%s",pd);
        if (pd[0]=='C') 
        {
            scanf("%d%d%d",&x,&y,&c);
            c++;
            cover(x,y,c);
        }
        if (pd[0]=='Q')
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",seg(x,y));
        }
    }
}

posted @ 2018-07-24 21:49  AGFghy  阅读(199)  评论(0编辑  收藏  举报