給定一棵有n個節點的無根樹和m個操做,操做有2類:php
1、將節點a到節點b路徑上全部點都染成顏色c;ui
2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認爲是同一段),如「112221」由3段組成:「11」、「222」和「1」。spa
請你寫一個程序依次完成這m個操做。blog
給定一棵有n個節點的無根樹和m個操做,操做有2類:php
1、將節點a到節點b路徑上全部點都染成顏色c;ui
2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認爲是同一段),如「112221」由3段組成:「11」、「222」和「1」。spa
請你寫一個程序依次完成這m個操做。blog
第一行包含2個整數n和m,分別表示節點數和操做數;ip
第二行包含n個正整數表示n個節點的初始顏色get
下面行每行包含兩個整數x和y,表示x和y之間有一條無向邊。string
下面行每行描述一個操做:hash
「C a b c」表示這是一個染色操做,把節點a到節點b路徑上全部點(包括a和b)都染成顏色c;it
「Q a b」表示這是一個詢問操做,詢問節點a到節點b(包括a和b)路徑上的顏色段數量。io
對於每一個詢問操做,輸出一行答案。
數N<=10^5,操做數M<=10^5,全部的顏色C爲整數且在[0, 10^9]之間。
解法:樹鏈剖分,用線段樹維護信息,重點就是合併兩個線段
假設是 11211333 3321122
一個seg記錄最左邊的顏色,最右邊的顏色, 答案,三個值
合併的話就是seg[rt].ans = seg[rt << 1].ans + seg[rt << 1 | 1].ans - (seg[rt << 1].r == seg[rt << 1 | 1].l);
有個trick,顏色是[0,10^9]的,因此0那個地方要注意注意~,下放標記的時候嗯啊
還有個要注意的是,算答案的時候要動態合併
就說你提取出來哪些線段,想象一下整個過程,是x,y不斷往lca走的過程,那麼開兩個值分別記錄x走的時候最「上」端的顏色,y最上端的顏色,最後一步lca那個特殊判一下就行
/* Author:wuhuajun */ #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define lson l, mid, rt << 1 #define rson mid+1, r, rt << 1 | 1 using namespace std; typedef long long ll; typedef double dd; const int maxn=100010; int edge, n, fa[maxn], sz[maxn], son[maxn], dep[maxn], hash[maxn], top[maxn]; int h[maxn], num, a[maxn], x, y, tx, ty, Q, col, ans, lcol, rcol; char s[22]; struct Edge { int to, ne; } e[maxn * 2]; struct Seg { int ans, l, r, same; void clear() { ans = l = r = same = 0; } } seg[maxn << 2]; void close() { exit(0); } void addedge(int x,int y) { e[edge].to = y; e[edge].ne = h[x]; h[x] = edge++; } void dfs(int k,int from) { sz[k] = 1; son[k] = 0; dep[k] = dep[from] + 1; for (int p=h[k];p!=-1;p=e[p].ne) { int to = e[p].to; if (from == to) continue; fa[to] = k; dfs(to, k); sz[k] += sz[to]; if (sz[to] > sz[son[k]]) son[k] = to; } } void build(int k,int from) { hash[k] = ++num; top[k] = from; if (son[k]) build(son[k], from); for (int p=h[k];p!=-1;p=e[p].ne) { int to = e[p].to; if (to != fa[k] && to != son[k]) build(to, to); } } //{{{Segment部分 void pushup(int rt) { seg[rt].l = seg[rt << 1].l; seg[rt].r = seg[rt << 1 | 1].r; seg[rt].ans = seg[rt << 1].ans + seg[rt << 1 | 1].ans - (seg[rt << 1].r == seg[rt << 1 | 1].l); } void same(int rt,int col) { seg[rt].same = col; seg[rt].l = seg[rt].r = col; seg[rt].ans = 1; } void pushdown(int rt) { if (seg[rt].same) { same(rt << 1, seg[rt].same); same(rt << 1 | 1, seg[rt].same); seg[rt].same = 0; } } void change(int L,int R,int val,int l,int r,int rt) { if (L <= l && r <= R) { same(rt, val); return; } int mid = (l + r) >> 1; pushdown(rt); if (L <= mid) change(L,R,val,lson); if (mid + 1 <= R) change(L,R,val,rson); pushup(rt); } Seg query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) { return seg[rt]; } int mid = (l + r) >> 1; Seg ans,a,b; ans.clear(); a.clear(); b.clear(); pushdown(rt); if (L <= mid) a = query(L,R,lson); if (mid + 1 <= R) b = query(L,R,rson); ans.ans = a.ans + b.ans; ans.l = a.l; ans.r = b.r; if (b.l == 0) ans.r = a.r; if (a.l == 0) ans.l = b.l; if (b.l != 0 && a.l != 0) { ans.ans -= (a.r == b.l); } pushup(rt); return ans; } //}}} // void work() { tx = top[x]; ty = top[y]; while (tx != ty) { if (dep[tx] < dep[ty]) { swap(tx, ty); swap(x, y); } change(hash[tx], hash[x], col, 1, n, 1); x = fa[tx]; tx = top[x]; } if (dep[x] > dep[y]) swap(x, y); change(hash[x], hash[y], col, 1, n, 1); } int get_ans() { ans = 0; tx = top[x]; ty = top[y]; lcol = rcol = 0; while (tx != ty) { if (dep[tx] < dep[ty]) { Seg haha = query(hash[ty], hash[y], 1, n, 1); //printf("ty:%d y:%d lcol:%d rcol:%d l:%d r:%d haha.ans:%d\n",ty,y,lcol,rcol,haha.l,haha.r,haha.ans); ans += haha.ans; if (haha.r == rcol) ans--; rcol = haha.l; y = fa[ty]; ty = top[y]; } else { Seg haha = query(hash[tx], hash[x], 1, n, 1); //printf("tx:%d x:%d lcol:%d rcol:%d l:%d r:%d haha.ans:%d\n",tx,x,lcol,rcol,haha.l,haha.r,haha.ans); ans += haha.ans; if (haha.r == lcol) ans--; lcol = haha.l; x = fa[tx]; tx = top[x]; } } if (dep[x] > dep[y]) { Seg haha = query(hash[y], hash[x], 1, n, 1); //printf("y:%d x:%d rcol:%d haha.r:%d haha.ans:%d\n",y,x,rcol,haha.r,haha.ans); ans += haha.ans; if (haha.r == lcol) ans--; if (haha.l == rcol) ans--; } else { Seg haha = query(hash[x], hash[y], 1, n, 1); //printf("x:%d y:%d lcol:%d haha.r:%d haha.ans:%d\n",x,y,lcol,haha.r,haha.ans); ans += haha.ans; if (haha.r == rcol) ans--; if (haha.l == lcol) ans--; } //puts(""); return ans; } void init() { scanf("%d %d",&n,&Q); for (int i=1;i<=n;i++) { scanf("%d", &a[i]); a[i]++; } memset(h,-1,sizeof(h)); for (int i=1;i<=n-1;i++) { scanf("%d %d",&x, &y); addedge(x, y); addedge(y, x); } dfs(1, 0); build(1, 1); for (int i=1;i<=n;i++) change(hash[i], hash[i], a[i], 1, n, 1); /* for (int i=1;i<=n;i++) { printf("i:%d top:%d hash:%d\n",i, top[i], hash[i]); } */ while (Q--) { scanf("%s %d %d",s,&x,&y); if (s[0] == 'C') { scanf("%d",&col); col++; work(); continue; } printf("%d\n",get_ans()); } } int main () { init(); close(); return 0; }