【思路】:
涉及到树上区间修改操作,所以使用树链剖分,涉及到区间查询,所以使用线段树。
update操作时,就正常操作,难点在于query操作的计数。
因为树链剖分的dfs序只能保证一条重链上的dfn[]连续,不能使得任意两点之间简单路径上的dfn[]连续,所以当x往上跳到fa[top[x]]时,要判断
top[x]的颜色与fa[top[x]]的颜色是否相同,如果相同要再减一。
以及在线段树中query操作和pushUp时,都要判断左儿子的右端点与右儿子的左端点是否相同,如果在pushUp中相同,则令此时的segtree[id]减一,
如果在query中相同,那么使得query函数返回的结果减一。 接下来上代码。
#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + ;
int n, m, a[maxn];
int segtree[maxn<<], lazy[maxn<<], lft[maxn<<], rht[maxn<<];
int head[maxn], tot, cnt;
int fa[maxn], top[maxn], dfn[maxn], rk[maxn], siz[maxn], dep[maxn], son[maxn];
struct edge{
int to,next;
} ed[maxn<<];
inline int read(){
int k=, f=;
char ch=getchar();
while( ch>'' || ch<'' ){ if(ch=='-') f=-; ch=getchar(); }
while( ch>='' && ch<='' ){ k=k*+ch-''; ch=getchar(); }
return k*f;
} inline void init(){
memset( head ,-, sizeof(head) );
memset( lazy, -, sizeof(lazy) );
tot = ;
} inline void add( int u, int v ){
ed[++tot].to = v; ed[tot].next = head[u]; head[u] = tot;
ed[++tot].to = u; ed[tot].next = head[v]; head[v] = tot;
} inline void dfs1( int x ){
siz[x] = ;
for( int i=head[x]; ~i; i=ed[i].next ){
int y = ed[i].to;
if( y==fa[x] ) continue;
dep[y] = dep[x]+;
fa[y] = x;
dfs1(y);
siz[x] += siz[y];
if( son[x]== || siz[y]>siz[son[x]] ) son[x] = y;
}
} inline void dfs2( int x, int tp ){
top[x] = tp;
dfn[x] = ++cnt;
rk[cnt] = x;
if( son[x] ) dfs2( son[x], tp );
for( int i=head[x]; ~i; i=ed[i].next ){
int y = ed[i].to;
if( y!=fa[x] && y!=son[x] ) dfs2(y, y);
}
} inline void pushUp( int id ){
segtree[id] = segtree[id<<] + segtree[id<<|];
if( lft[id<<|]==rht[id<<] ) segtree[id] --;
lft[id] = lft[id<<]; rht[id] = rht[id<<|];
} inline void pushDown( int id ){
if( lazy[id]==- ) return;
lazy[id<<] = lazy[id<<|] = lazy[id];
segtree[id<<] = segtree[id<<|] = ;
lft[id<<] = lft[id<<|] = rht[id<<] = rht[id<<|] = lazy[id];
lazy[id] = -;
} inline void build( int l, int r, int id ){
if( l==r ){
lft[id] = rht[id] = a[rk[l]];
segtree[id] = ;
return ;
}
int mid=l+r>>;
build( l, mid, id<< );
build( mid+, r, id<<| );
pushUp(id);
} inline void update_tree( int l, int r, int ql, int qr, int id, int c ){
if( ql<=l && qr>=r ){
segtree[id] = ;
lft[id] = rht[id] = c;
lazy[id] = c;
return ;
}
pushDown(id);
int mid = l+r>>;
if( ql<=mid ) update_tree( l, mid, ql, qr, id<<, c );
if( qr>mid ) update_tree( mid+, r, ql, qr, id<<|, c );
pushUp(id);
} inline int query( int l, int r, int ql, int qr, int id ){
if( ql<=l && qr>=r ) return segtree[id];
pushDown(id);
int mid = l+r>>;
int res = ;
if( ql<=mid ) res += query( l, mid, ql, qr, id<< );
if( qr>mid ) res += query( mid+, r, ql, qr, id<<| );
if( ql<=mid && qr>mid && lft[id<<|]==rht[id<<] ) res--; //这里也要判断一次是否相同,前提是要跨立区间
return res;
} inline int color_query( int l, int r, int idx, int id ){
if( l==r ) return lft[id];
pushDown(id);
int mid = l+r>>;
if( idx<=mid ) return color_query( l, mid, idx, id<< );
else return color_query( mid+, r, idx, id<<| );
} inline void swap( int &x, int &y ){ x^=y^=x^=y; } inline int sum( int x, int y ){
int res = ;
while( top[x]!=top[y] ){
if( dep[top[x]]<dep[top[y]] ) swap(x, y);
res += query(, n, dfn[top[x]], dfn[x], );
if( color_query(, n, dfn[top[x]], )==color_query(, n, dfn[fa[top[x]]], ) ) res --; //颜色相同减一
x = fa[top[x]];
}
if( dfn[x]>dfn[y] ) swap(x, y);
res += query( , n, dfn[x], dfn[y], );
return res== ? :res;
} inline void update_chain( int x, int y, int c ){
while( top[x]!=top[y] ){
if( dep[top[x]]<dep[top[y]] ) swap(x, y);
update_tree(, n, dfn[top[x]], dfn[x], , c );
x = fa[top[x]];
}
if( dfn[x]>dfn[y] ) swap(x, y);
update_tree( , n, dfn[x], dfn[y], , c );
} int main(){
// freopen("in.txt", "r", stdin);
init();
n = read(); m = read();
for( int i=; i<=n; i++ ) a[i] = read();
for( int i=; i<n; i++ ){
int u=read(), v=read();
add(u, v);
}
dep[] = fa[] = ;
dfs1();
dfs2(, );
build( , n, );
char ch[];
while( m-- ){
int x, y, z;
scanf("%s", ch);
x = read(); y = read();
if( ch[]=='Q' ) printf("%d\n", sum(x, y));
else{
z = read();
update_chain(x, y, z);
}
} return ;
}