很长时间没写博客了~~
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27552
算法:路径剖分+LCA+线段树
思路:详见漆子超的论文《分治算法在树的路径问题中的应用》,becauseofyou整理的树链剖分模板。线段树统计每条重边末尾的节点的值。
还有普通线段树+LCA的做法
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define mid int m = (l+r) >> 1
const int M = 100005;
int head[M], color[11][M << 2];
int dep[M], rev[M], num[M << 1], size[M];
int temp[11], f[M], heavy[M], a[M];
struct Edge{
int v, next;
} edge[M << 1];
int tot = 0, n;
int maxz(int a, int b){return a > b ? a : b;}
void add_edge(int s, int v){
edge[tot].v = v;
edge[tot].next = head[s];
head[s] = tot ++;
}
void inti(){
memset(head, -1, sizeof(head));
memset(color, 0, sizeof(color));
memset(num, -1, sizeof(num));
memset(heavy, -1, sizeof(heavy));
dep[1] = 0;
tot = 0;
for(int i = 0; i <= n; i ++) f[i] = i;
}
void dfs(int u, int fa){
int mx = -1, e = -1;
size[u] = 1;
for(int i = head[u]; i!=-1; i = edge[i].next){
int v = edge[i].v;
if(v == fa) continue;
dep[v] = dep[u] + 1;
rev[v] = i ^ 1;
dfs(v, u);
size[u] += size[v];
if(size[v] > mx){
mx = size[v];
e = i;
}
}
heavy[u] = e;
if(e != -1) f[edge[e].v] = u;
}
void PushUp(int rt){
for(int i = 1; i <= 10; i ++)
color[i][rt] = color[i][rt << 1] + color[i][rt << 1 | 1];
}
void update(int d, int k, int l, int r, int rt, int op, int ans){
if(l == r){
if(op == -1){
color[k][rt] --;
}
color[ans][rt] ++;
return ;
}
mid;
if(d <= m) update(d, k, lson, op, ans);
else update(d, k, rson, op, ans);
PushUp(rt);
}
void prepare(){
dfs(1, -1);
int N = 0;
for(int i = 1; i <= n; i ++){
if(heavy[i] == -1){
int pos = i;
while(pos != 1 && pos == edge[heavy[edge[rev[pos]].v]].v){
// printf("pos = %d\n", pos);
int e = rev[pos];
num[e] = num[e^1] = ++ N;
update(N, a[pos], 1, n, 1, 1, a[pos]);
pos = edge[e].v;
}
}
}
}
void change(int d, int b){
if(d == 1){ a[d] = b; }
else if(num[rev[d]] == -1) a[d] = b;
else{
update(num[rev[d]], a[d], 1, n, 1, -1, b);
a[d] = b;
}
}
int find(int a){return a == f[a] ? a : f[a] = find(f[a]);}
int lca(int a, int b){
while(1){
int ra = find(a);
int rb = find(b);
if(ra == rb){return dep[a] < dep[b] ? a : b;}
else if(dep[ra] >= dep[rb]) a = edge[rev[ra]].v;
else b = edge[rev[rb]].v;
}
}
void query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R){
for(int i = 1; i <= 10; i ++)
temp[i] += color[i][rt];
return ;
}
mid;
if(L <= m) query(L, R, lson);
if(m < R) query(L, R, rson);
PushUp(rt);
}
void cala(int u, int lca){
while(u != lca){
int e = rev[u];
if(num[e] == -1){
temp[a[u]] ++;
u = edge[e].v;
}else {
int p = f[u];
if(dep[p] < dep[lca]) p = lca;
int l = num[e];
int r = num[heavy[p]];
query(l, r, 1, n, 1);
u = p;
}
}
}
int solve(int c, int b){
int i;
int p = lca(c, b);
memset(temp, 0, sizeof(temp));
cala(c, p);
cala(b, p);
temp[a[p]] ++;
int maxn = 0;
for(i = 1; i <= 10; i ++){
maxn = maxz(maxn, temp[i]);
}
return maxn;
}
int main(){
int T;
int m;
scanf("%d", &T);
while(T --){
scanf("%d%d", &n, &m);
int i, b, c;
inti();
for(i = 1; i <= n; i ++){
scanf("%d", &a[i]);
}
for(i = 0; i < n-1; i ++){
scanf("%d%d", &b, &c);
add_edge(b, c);
add_edge(c, b);
}
prepare();
int op;
while(m --){
scanf("%d%d%d", &op, &b, &c);
if(op == 1){
printf("%d\n", solve(b, c));
}else {
change(b, c);
}
}
}
return 0;
}