首页 > 代码库 > [SPOJ10707]Count on a tree II

[SPOJ10707]Count on a tree II

[SPOJ10707]Count on a tree II

试题描述

You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.

We will ask you to perform the following operation:

  • u v : ask for how many different integers that represent the weight of nodes there are on the path from u to v.

输入

In the first line there are two integers N and M. (N <= 40000, M <= 100000)

In the second line there are N integers. The i-th integer denotes the weight of the i-th node.

In the next N-1 lines, each line contains two integers u v, which describes an edge (u, v).

In the next M lines, each line contains two integers u v, which means an operation asking for how many different integers that represent the weight of nodes there are on the path from u to v.

输出

For each operation, print its result.

输入示例

8 2
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5
7 8

输出示例

4
4

数据规模及约定

见“输入

题解

树上莫队。

就是树上分块(见上一题);接着对询问路径按照左端点所在块为第一关键字,右端点 dfs 序为第二关键字(随便让哪个点作为左端点都无所谓);然后暴力从一条路径 (a, b) 更新到另一条路径 (a‘, b‘)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
	return x * f;
}

#define maxn 50010
#define maxm 100010
#define maxq 100010
#define maxlog 17

int n, m, head[maxn], nxt[maxm], to[maxm], col[maxn], num[maxn];

void AddEdge(int a, int b) {
	to[++m] = b; nxt[m] = head[a]; head[a] = m;
	swap(a, b);
	to[++m] = b; nxt[m] = head[a]; head[a] = m;
	return ;
}

int fa[maxn], dep[maxn], mnp[maxlog][maxn<<1], dfn[maxn], clo, Bsiz, blid[maxn], cb, S[maxn], top;
void build(int u) {
	dfn[u] = ++clo; mnp[0][clo] = u;
	int bot = top;
	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u]) {
		fa[to[e]] = u; dep[to[e]] = dep[u] + 1;
		build(to[e]); mnp[0][++clo] = u;
		if(top - bot >= Bsiz) {
			cb++;
			while(top > bot) blid[S[top--]] = cb;
		}
	}
	S[++top] = u;
	return ;
}
int Log[maxn<<1];
void rmq_init() {
	Log[1] = 0;
	for(int i = 2; i <= clo; i++) Log[i] = Log[i>>1] + 1;
	for(int j = 1; (1 << j) <= clo; j++)
		for(int i = 1; i + (1 << j) - 1 <= clo; i++) {
			int a = mnp[j-1][i], b = mnp[j-1][i+(1<<j-1)];
			mnp[j][i] = dep[a] < dep[b] ? a : b;
		}
	return ;
}
int lca(int a, int b) {
	int l = dfn[a], r = dfn[b];
	if(l > r) swap(l, r);
	int t = Log[r-l+1];
	a = mnp[t][l]; b = mnp[t][r-(1<<t)+1];
	return dep[a] < dep[b] ? a : b;
}

int q;
struct Que {
	int u, v, id;
	Que() {}
	Que(int _1, int _2, int _3): u(_1), v(_2), id(_3) {}
	bool operator < (const Que& t) const { return blid[u] != blid[t.u] ? blid[u] < blid[t.u] : dfn[v] < dfn[t.v]; }
} qs[maxq];

int U, V, ans, tot[maxn], Ans[maxq];
bool tag[maxn];
void rev(int u) {
	if(tag[u]) {
		if(!--tot[col[u]]) ans--;
	}
	else {
		if(++tot[col[u]] == 1) ans++;
	}
	tag[u] ^= 1;
	return ;
}
void change(int& node, int tar) {
	int c = lca(node, tar), c2 = lca(U, V);
	bool has = 0;
	while(node != c) rev(node), node = fa[node];
	int ttar = tar;
	while(tar != c) rev(tar), tar = fa[tar];
	rev(c);
	node = ttar;
	int c3 = lca(U, V);
	if(dep[c] < dep[c2]) c = c2;
	if(dep[c] < dep[c3]) c = c3;
	rev(c);
	return ;
}

int main() {
	n = read(); q = read();
	for(int i = 1; i <= n; i++) num[i] = col[i] = read();
	sort(num + 1, num + n + 1);
	for(int i = 1; i <= n; i++) col[i] = lower_bound(num + 1, num + n + 1, col[i]) - num;
	for(int i = 1; i < n; i++) {
		int a = read(), b = read();
		AddEdge(a, b);
	}
	Bsiz = sqrt(n + .5);
	build(1);
	while(top) blid[S[top--]] = cb;
	rmq_init();
	
	for(int i = 1; i <= q; i++) {
		int a = read(), b = read();
		qs[i] = Que(a, b, i);
	}
	sort(qs + 1, qs + q + 1);
	
	U = V = ans = tot[col[1]] = tag[1] = 1;
	for(int i = 1; i <= q; i++) {
		change(U, qs[i].u);
		change(V, qs[i].v);
		Ans[qs[i].id] = ans;
	}
	for(int i = 1; i <= q; i++) printf("%d\n", Ans[i]);
	
	return 0;
}

 

[SPOJ10707]Count on a tree II