[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;
}
时间: 2024-10-29 19:05:47

[SPOJ10707]Count on a tree II的相关文章

「SPOJ10707」Count on a tree II

「SPOJ10707」Count on a tree II 传送门 树上莫队板子题. 锻炼基础,没什么好说的. 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w

spoj COT2 - Count on a tree II

COT2 - Count on a tree II http://www.spoj.com/problems/COT2/ #tree 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

AC日记——Count on a tree II spoj

Count on a tree II 思路: 树上莫队: 先分块,然后,就好办了: 来,上代码: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 40005 #define maxm 100005 struct QueryType { in

Count on a tree II(树上莫队)

Count on a tree II(luogu) Description 题目描述 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. 输入格式 第一行有两个整数n和m(n=40000,m=100000). 第二行有n个整数.第i个整数表示第i个节点表示的整数. 在接下来的n-1行中,每行包含两个整数u v,描述一条边(u,v). 在接下来的m行中,每一行包含两个整数u v,询问u到v的路径上有多少个不同的整数. 输出格式 对于每个询问,输出结果. Solutio

SPOJ10707 COT2 - Count on a tree II 【树上莫队】

题目分析: 考虑欧拉序,这里的欧拉序与ETT欧拉序的定义相同而与倍增LCA不同.然后不妨对于询问$u$与$v$让$dfsin[u] \leq dfsin[v]$,这样对于u和v不在一条路径上,它们可以改成询问$dfsin[u]$到$dfsin[v]$.否则改成$dfsout[u]$到$dfsin[v]$,并加上LCA上的影响,如果在询问过程中没有加入就加入,否则删除. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const

【SPOJ10707】COT2 - Count on a tree II

题目大意:给定一棵 N 个节点的无根树,每个节点有一个颜色.现有 M 个询问,每次询问一条树链上的不同颜色数. 题解:学会了树上莫队. 树上莫队是将节点按照欧拉序进行排序,将树上问题转化成序列上的问题进行求解的算法.需要分两种情况进行讨论,第一种情况是对于询问 x,y 来说,x 为 y 的祖先,则询问的区间为 \(st[x],st[y]\),第二种情况是 x 与 y 处在两个不同的子树内,这时发现 \(lca(x,y)\) 的欧拉序并不在 [ed[x], st[y]] 内,因此需要额外考虑 lc

SPOJ COT2 Count on a tree II(树上莫队)

题目链接:http://www.spoj.com/problems/COT2/ 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 perfrom the following operation: u v : ask for how many different integers that repr

bzoj2589: Spoj 10707 Count on a tree II

Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v),表示一组询问. 数据范围是N<=40000 M<=100000 点权在int范围内

SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无意中看到树上莫队,只是拿来练练,没有想到这题的难点不在于树上莫队,而是判断LCA是否在两点之间的路径上的问题.耗时1天. 树上莫队的搞法就是: (1)DFS一次,对树进行分块,分成sqrt(n)块,每个点属于一个块.并记录每个点的DFS序. (2)将m个询问区间用所属块号作为第一关键字,DFS序作为第二关键字