BZOJ2243/SDOI2011/染色

Posted on By 二价氢

#题目描述

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

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

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

#做法

树链剖分x线段树模版题

#AC Code

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
const int maxn=444444;
const int ls(const int &x){return x<<1;}
const int rs(const int &x){return x<<1|1;}
struct tree{
    int l,r,c;
    tree(int _l=-1,int _r=-1,int _c=0):l(_l),r(_r),c(_c){}
    friend tree operator + (const tree &s,const tree &t)
    {
        return (s.l==-1)?(t):((t.l==-1)?(s):(tree(s.l,t.r,s.c+t.c-(s.r==t.l))));
    }
}T[maxn];
//--
int color[maxn],pos[maxn],seg[maxn],lazy[maxn];
int top[maxn],h[maxn],dep[maxn],sz[maxn];
int n,m,id;
int q[maxn],fa[maxn],qf,qt;
vector <int> e[maxn];
vector <int>::iterator vi;
void set(int x,int v)
{
    T[x]=tree(lazy[x]=v,v,1);
}
void push(int x)
{
    if (~lazy[x])
    {
        set(ls(x),lazy[x]);
        set(rs(x),lazy[x]);
        lazy[x]=-1;
    }
}
void build(int x,int l,int r)
{
    lazy[x]=-1;
    if (l==r)
    {
        T[x]=tree(seg[l],seg[l],1);
        return;
    }
    int mid=(l+r)/2;
    if (l<=mid)
        build(ls(x),l,mid);
    if (r>mid)
        build(rs(x),mid+1,r);
    T[x]=T[ls(x)]+T[rs(x)];
}
void paint(int x,int l,int r,int cl,int cr,int c)
{
    if (cl<=l && cr>=r)
    {
        set(x,c);
        return;
    }
    push(x);
    int mid=(l+r)/2;
    if (cl<=mid)
        paint(ls(x),l,mid,cl,cr,c);
    if (cr>mid)
        paint(rs(x),mid+1,r,cl,cr,c);
    T[x]=T[ls(x)]+T[rs(x)];
}
tree query(int x,int l,int r,int ql,int qr)
{
    if (ql<=l && qr>=r)
        return T[x];
    tree tl,tr;
    push(x);
    int mid=(l+r)/2;
    if (ql<=mid)
        tl=query(ls(x),l,mid,ql,qr);
    if (qr>mid)
        tr=query(rs(x),mid+1,r,ql,qr);
    return tl+tr;
}
void paint(int x,int y,int c)
{
    while (top[x]!=top[y])
        if (dep[top[x]]>dep[top[y]])
            paint(1,1,n,pos[top[x]],pos[x],c),x=fa[top[x]];
        else
            paint(1,1,n,pos[top[y]],pos[y],c),y=fa[top[y]];
    if (dep[x]>dep[y])
        paint(1,1,n,pos[y],pos[x],c);
    else
        paint(1,1,n,pos[x],pos[y],c);
}
int query(int x,int y)
{
    tree l,r;
    while (top[x]!=top[y])
        if (dep[top[x]]>dep[top[y]])
            l=query(1,1,n,pos[top[x]],pos[x])+l,x=fa[top[x]];
        else
            r=query(1,1,n,pos[top[y]],pos[y])+r,y=fa[top[y]];
    if (dep[x]>dep[y])
        l=query(1,1,n,pos[y],pos[x])+l;
    else
        r=query(1,1,n,pos[x],pos[y])+r;
    swap(l.l,l.r);
    return (l+r).c;
}
int main()
{
    char op[5];
    int u,v,c;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&color[i]);
    for (int i=1;i<n;i++)
        scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u);
    q[qf=qt=1]=1;dep[1]=1;
    for (;qf<=qt;qf++)
    {
        u=q[qf];
        for (vi=e[u].begin();vi!=e[u].end();vi++)
        {
            if (!dep[*vi])
            {
                dep[*vi]=dep[u]+1;
                fa[*vi]=u;
                q[++qt]=*vi;
            }
        }
    }
    fa[1]=0;
    for (int i=qt;i>=1;i--)
    {
        u=q[i];
        sz[fa[u]]+=++sz[u];
        if (sz[u]>sz[h[fa[u]]])
            h[fa[u]]=u;
    }
    for (int i=1;i<=qt;i++)
    {
        u=q[i];
        if (!top[u])
            for(v=u;v;v=h[v])
            {
                top[v]=u;
                pos[v]=++id;
                seg[id]=color[v];
            }
    }
    memset(lazy,-1,sizeof(lazy));
    build(1,1,n);
    for (int i=1;i<=m;i++)
    {
        scanf("%s",op);
        if (op[0]=='C')
            scanf("%d%d%d",&u,&v,&c),paint(u,v,c);
        else
            scanf("%d%d",&u,&v),printf("%d\n",query(u,v));
    }
    return 0;
}