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

第一轮day1

首先用树剖和线段树处理

这时线段树记录的信息有a[x].l表示这段区间最左边的颜色编号,a[x].r表示这段区间最右边的颜色编号,a[x].s表示颜色数

在push up的时候,a[x].s=a[ls].s+a[rs].s,如果a[ls].r==a[rs].l就说明重复计入了一个,那么就要讲a[x].s--;

在查询答案时也要注意这一点,对于分别查询的两个区间之间要进行颜色是否相同的判断,对于链与链之间也要进行相同的判断。

#include<cstdio>
#include<algorithm>
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int N=1e5+5;
struct Y
{
    int v,f,n;
}y[N<<1];
struct A
{
    int l,r,s,lz;
    void fz(int g)
    {
        l=r=lz=g;
        s=1;
    }
}a[N<<2];
int s,ss,siz[N],fa[N],co[N],dfn[N],tou[N],hson[N],n;
void add(int u,int v)
{
    y[++s].v=v;
    y[s].n=y[u].f;
    y[u].f=s;
}
void dfs1(int u)
{
    siz[u]=1;
    for(int i=y[u].f;i;i=y[i].n)
        if(y[i].v!=fa[u])
        {
            fa[y[i].v]=u;
            dfs1(y[i].v);
            siz[u]+=siz[y[i].v];
            if(siz[y[i].v]>siz[hson[u]]) hson[u]=y[i].v;
        }
}
void dfs2(int u,int to)
{
    dfn[u]=++ss;
    tou[u]=to;
    if(hson[u]) dfs2(hson[u],to);
    for(int i=y[u].f;i;i=y[i].n)
        if(y[i].v!=hson[u]&&y[i].v!=fa[u]) dfs2(y[i].v,y[i].v);
}
void pd(int x,int l,int r,int mid)
{
    if(a[x].lz)
    {
        a[ls].fz(a[x].lz),a[rs].fz(a[x].lz);
        a[x].lz=0;
    }
}
void chan(int x,int l,int r,int ql,int qr,int z)
{
    if(ql<=l&&r<=qr) a[x].fz(z);
    else
    {
        int mid=(l+r)>>1;
        pd(x,l,r,mid);
        if(ql<=mid) chan(ls,l,mid,ql,qr,z);
        if(qr>mid) chan(rs,mid+1,r,ql,qr,z);
        a[x].l=a[ls].l;a[x].r=a[rs].r;
        a[x].s=a[ls].s+a[rs].s;
        if(a[ls].r==a[rs].l) --a[x].s;
    }
}
int askk(int x,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return a[x].s;
    int mid=(l+r)>>1,re=0;
    pd(x,l,r,mid);
    if(ql<=mid) re+=askk(ls,l,mid,ql,qr);
    if(qr>mid) re+=askk(rs,mid+1,r,ql,qr);
    if(ql<=mid&&qr>mid&&a[ls].r==a[rs].l) --re;
    return re;
}
int gc(int x,int l,int r,int wz)
{
    if(l==r) return a[x].lz;
    int mid=(l+r)>>1;
    pd(x,l,r,mid);
    if(wz<=mid) return gc(ls,l,mid,wz);
    else return gc(rs,mid+1,r,wz);
}
int qu(int u,int v)
{
    int re=0;
    while(tou[u]!=tou[v])
    {
        if(dfn[u]<dfn[v]) swap(u,v);
        re+=askk(1,1,n,dfn[tou[u]],dfn[u]);
        if(gc(1,1,n,dfn[tou[u]])==gc(1,1,n,dfn[fa[tou[u]]])) --re;
        u=fa[tou[u]];
    }
    if(dfn[u]<dfn[v]) swap(u,v);
    re+=askk(1,1,n,dfn[v],dfn[u]);
    return re;
}
int main()
{
    int m,u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%d",&co[i]);
    for(int i=2;i<=n;++i)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs1(1);
    dfs2(1,1);
    for(int i=1;i<=n;++i)
        chan(1,1,n,dfn[i],dfn[i],co[i]+1);
    while(m--)
    {
        char c[5];
        int cc;
        scanf("%s%d%d",c,&u,&v);
        if(c[0]=='Q') printf("%d\n",qu(u,v));
        else
        {
            scanf("%d",&cc);++cc;
            while(tou[u]!=tou[v])
            {
                if(dfn[u]<dfn[v]) swap(u,v);
                chan(1,1,n,dfn[tou[u]],dfn[u],cc);
                u=fa[tou[u]];
            }
            if(dfn[u]<dfn[v]) swap(u,v);
            chan(1,1,n,dfn[v],dfn[u],cc);
        }
    }
    return 0;
}