链接 : http://www.lydsy.com/JudgeOnline/problem.php?id=2243
中文题。
思路 : 很裸的树链剖分, 而查询颜色段数量可以用线段树来维护, 唯一麻烦的是在查询的时候要注意每一段的有向性,
即 a----b + c----d 的时候要注意不能更新成a----b + d----c
这里写的时候需要斟酌下(其实考虑到top[u]在线段树上的位置比u在线段树上的位置要小就容易做了的),另外,在最后一次并的时候需要变换下其中一个的l和r。
贴下代码, 防止过完年后忘的干干净净。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long lld;
const int maxn = 100005;
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
struct Edge{
int v, next;
}edge[maxn<<1];
struct N{
int num, l, r;
}que[maxn<<2];
int n, m, M, head[maxn], E, tot;
int top[maxn], Fa[maxn], Dep[maxn], Son[maxn], Siz[maxn];
int w[maxn], W[maxn], val[maxn], cov[maxn<<2];
N Up(N L, N R){
if (!L.num)return R;
if (!R.num)return L;
N ans;
ans.num = L.num + R.num - (L.r == R.l);
ans.l = L.l; ans.r = R.r;
return ans;
}
void Down(int rt){
if (cov[rt] != -1){
cov[rt<<1] = cov[rt<<1|1] = cov[rt];
que[rt<<1] = que[rt<<1|1] = (N){1, cov[rt], cov[rt]};
cov[rt] = -1;
}
}
void build(int rt, int l, int r){
cov[rt] = -1;
if (l == r){
que[rt] = (N){1, W[l], W[r]};
return ;
}
int mid = r + l >> 1;
build(lson); build(rson);
que[rt] = Up(que[rt<<1], que[rt<<1|1]);
}
void update(int rt, int l, int r, int L, int R, int c){
if (l >= L && r <= R){
cov[rt] = c;
que[rt] = (N){1, c, c};
return ;
}
Down(rt);
int mid = r + l >> 1;
if (mid >= L)update(lson, L, R, c);
if (R > mid) update(rson, L, R, c);
que[rt] = Up(que[rt<<1], que[rt<<1|1]);
}
N query(int rt, int l, int r, int L, int R){
if (l >= L && r <= R){
return que[rt];
}
Down(rt);
int mid = r + l >> 1;
N res = (N){0, -1, -1};
if (mid >= L)res = query(lson, L, R);
if (R > mid){
if (res.num)return Up(res, query(rson, L, R));
else return query(rson, L, R);
}
return res;
}
void init(){
E = 0; tot = 0; top[1] = 1;
memset(head, -1, sizeof(head));
}
void add_edge(int u, int v){
edge[E].v = v;
edge[E].next = head[u];
head[u] = E++;
}
void dfs1(int fa, int u, int d){
Fa[u] = fa; Dep[u] = d; Siz[u] = 1; Son[u] = -1;
int Max = 0;
for (int i = head[u]; i != - 1; i = edge[i].next){
int v = edge[i].v;
if (v == fa)continue;
dfs1(u, v, d + 1);
Siz[u] += Siz[v];
if (Siz[v] > Max){
Max = Siz[v];
Son[u] = v;
}
}
return ;
}
void dfs2(int fa, int u){
w[u] = ++tot; W[tot] = val[u];
if (Son[u] == -1)return ;
for (int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].v;
if (v != Son[u])continue;
top[v] = top[u];
dfs2(u, v);
}
for (int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].v;
if (v == fa || v == Son[u])continue;
top[v] = v;
dfs2(u, v);
}
}
void C(int a, int b, int c){
while (top[a] != top[b]){
int f1 = top[a], f2 = top[b];
if (Dep[f1] >= Dep[f2]){
update(1, 1, m, w[f1], w[a], c);
a = Fa[f1];
}else {
update(1, 1, m, w[f2], w[b], c);
b = Fa[f2];
}
}
if (Dep[a] >= Dep[b]){
update(1, 1, m, w[b], w[a], c);
}else {
update(1, 1, m, w[a], w[b], c);
}
}
N Q(int a, int b){
N L, R;
L = R = (N){0, -1, -1};
if (top[a] != top[b]){
while (top[a] != top[b]){
int f1 = top[a], f2 = top[b];
if (Dep[f1] >= Dep[f2]){
L = Up(query(1, 1, m, w[f1], w[a]), L);
a = Fa[f1];
}else {
R = Up(query(1, 1, m, w[f2], w[b]), R);
b = Fa[f2];
}
}
if (Dep[a] >= Dep[b]){
L = Up(query(1, 1, m, w[b], w[a]), L);
}else {
R = Up(query(1, 1, m, w[a], w[b]), R);
}
swap(L.l, L.r);
return Up(L, R);
}else {
if (Dep[a] >= Dep[b])return query(1, 1, m, w[b], w[a]);
else return query(1, 1, m, w[a], w[b]);
}
}
int main(){
scanf("%d%d", &n, &M);
for (int i = 1; i <= n; i++){
scanf("%d", &val[i]);
}
init();
for (int i = 1; i < n; i++){
int a, b;
scanf("%d%d", &a, &b);
add_edge(a, b);
add_edge(b, a);
}
dfs1(0, 1, 0);
dfs2(0, 1);
m = tot;
build(1, 1, m);
while (M--){
char op[2];
int a, b, c;
scanf("%s%d%d", op, &a, &b);
if (op[0] == 'C'){
scanf("%d", &c);
C(a, b, c);
}else {
printf("%d\n", Q(a, b).num);
}
}
return 0;
}