UVA 12424 Answering Queries on a Tree

很長時間沒寫博客了~~

題目鏈接: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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章