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
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
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Source
PS:通过这道题我发现之前的LCT模板有点问题。。
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#define MAXN 100015
using namespace std;
int n,m,u,v,c,lc[MAXN],rc[MAXN],ch[MAXN][2],s[MAXN],a[MAXN],value[MAXN],fa[MAXN],lazy2[MAXN];
bool lazy[MAXN];
inline bool isroot(int x)
{
return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
void push_up(int x)
{
value[x] = 1;
if(ch[x][0])
{
if(rc[ch[x][0]] == a[x]) value[x] = value[ch[x][0]];
else value[x] += value[ch[x][0]];
lc[x] = lc[ch[x][0]];
}
else lc[x] = a[x];
if(ch[x][1])
{
if(lc[ch[x][1]] == a[x]) value[x] += value[ch[x][1]] - 1;
else value[x] += value[ch[x][1]];
rc[x] = rc[ch[x][1]];
}
else rc[x] = a[x];
}
void rotate(int x)
{
int y = fa[x],z = fa[y];
int d = ch[y][0] == x ? 0 : 1;
if(!isroot(y))
{
if(ch[z][0] == y) ch[z][0] = x;
else ch[z][1] = x;
}
fa[y] = x,fa[x] = z,fa[ch[x][d^1]] = y;
ch[y][d] = ch[x][d^1],ch[x][d^1] = y;
push_up(y),push_up(x);
}
void change(int x,int y)
{
lazy2[x] = y;
a[x] = lc[x] = rc[x] = y;
value[x] = 1;
}
inline void push_down(int x)
{
if(lazy[x])
{
int ls = ch[x][0],rs = ch[x][1];
lazy[x]^=1,lazy[ls]^=1;lazy[rs]^=1;
swap(ch[ls][0],ch[ls][1]);
swap(ch[rs][0],ch[rs][1]);
swap(lc[ls],rc[ls]);
swap(lc[rs],rc[rs]);
}
if(lazy2[x] >= 0)
{
change(ch[x][0],lazy2[x]),change(ch[x][1],lazy2[x]);
lazy2[x] = -1;
}
}
void splay(int x)
{
int tot = 0;s[++tot] = x;
for(int i = x;!isroot(i);i = fa[i]) s[++tot] = fa[i];
for(;tot;tot--) push_down(s[tot]);
while(!isroot(x))
{
int y = fa[x],z = fa[y];
if(!isroot(y))
{
if((ch[z][0] == y) ^ (ch[y][0] == x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
int t = 0;
while(x)
{
splay(x);
ch[x][1] = t; //parent path 边中儿子一定是子链root,父亲是子链root实际父亲
push_up(x);
t = x,x = fa[x];
}
}
void makeroot(int x) //x变成根
{
access(x),splay(x);
swap(ch[x][0],ch[x][1]);
lazy[x]^=1;
}
void link(int x,int y)
{
makeroot(x);fa[x] = y;
}
int main()
{
memset(lazy2,-1,sizeof(lazy2));
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
scanf("%d",&a[i]);
value[i] = 1;
lc[i] = rc[i] = a[i];
}
for(int i = 1;i < n;i++)
{
scanf("%d%d",&u,&v);
link(u,v);
}
for(int i = 1;i <= m;i++)
{
char op[2];
scanf("%s",op);
if(op[0] == 'C')
{
scanf("%d%d%d",&u,&v,&c);
makeroot(u);
access(v);
splay(v);
change(v,c);
}
else
{
scanf("%d%d",&u,&v);
makeroot(v);
access(u);
splay(u);
printf("%d\n",value[u]);
}
}
}