SPOJ-COT2 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.

Input

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 (uv).

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.

Output

For each operation, print its result.

Example

Input:
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
Output:
4

4

题意:给一棵染过色的数,每个点有一个颜色,每次询问树上一段路径的颜色数量。

分析: 树上莫队,通过dfs序可以把树上的一段路径转换为一段序列,剩下做法就和一般的序列莫队一样了。

#include 
#include 
#include 
#include 
#include 
#define N 40015 
using namespace std;
int n,m,ans,u,v,Time,block,Ans[100005],a[N],vis[N],s[N],rd[N],cd[N],deep[N],fh[2*N],color[N],f[N][31];
vector G[N];
struct thing
{
	int l,r,bl,lca,num;
	friend bool operator < (thing a,thing b)
	{
		if(a.bl == b.bl) return a.r < b.r;
		return a.bl < b.bl;
	}
}ask[100005];
void dfs(int u,int fa)
{
	deep[u] = deep[fa] + 1;
	f[u][0] = fa;
	rd[u] = ++Time;
	fh[Time] = u;
	for(int i = 0;i < G[u].size();i++)
	{
		int v = G[u][i];
		if(v != fa) dfs(v,u);
	}
	cd[u] = ++Time;
	fh[Time] = u;
}
void init()
{
	for(int j = 1;(1<= 0;i--)
	{
		if(f[u][i] != f[v][i])
		{
			u = f[u][i];
			v = f[v][i];	
		}	
	}
	u = f[u][0];
	return u; 
}
void updata(int u)
{
	if(vis[u])
	{
		if(!color[a[u]]) ans++;
		color[a[u]]++;
	}
	else 
	 if(!(--color[a[u]])) ans--;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++) 
	{
		scanf("%d",&a[i]);
		s[i] = a[i];
	}
	sort(s+1,s+1+n);
	for(int i = 1;i <= n;i++) a[i] = lower_bound(s+1,s+1+n,a[i]) - s;
	for(int i = 1;i < n;i++)
	{
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(n/2+1,0);
	init();
	block = (int)(2.82*n/sqrt(m)) + 1;
	for(int i = 1;i <= m;i++)
	{
		scanf("%d%d",&u,&v);
		ask[i].lca = LCA(u,v);
		ask[i].num = i;
		if(ask[i].lca == u || ask[i].lca == v)
		{
			ask[i].lca = -1;
			if(deep[u] > deep[v]) swap(u,v);
			ask[i].l = rd[u],ask[i].r = rd[v];
		}
		else 
		{
			if(cd[u] > rd[v]) swap(u,v);
			ask[i].l = cd[u],ask[i].r = rd[v];
		}
		ask[i].bl = (ask[i].l-1)/block + 1;
	}
	sort(ask+1,ask+1+m);
	int l = 1,r = 1;
	color[a[fh[1]]] = 1;
	vis[fh[1]] = 1;
	ans = 1;
	for(int i = 1;i <= m;i++)
	{
		for(;r > ask[i].r;r--)
		{
			vis[fh[r]] ^= 1;
			updata(fh[r]);
 		}
 		for(r++;r <= ask[i].r;r++)
 		{
 			vis[fh[r]] ^= 1;
			updata(fh[r]);	
		}
		for(;l < ask[i].l;l++)
		{
			vis[fh[l]] ^= 1;
			updata(fh[l]);
		}
		for(l--;l >= ask[i].l;l--)
		{
			vis[fh[l]] ^= 1;
			updata(fh[l]);
		}
		if(ask[i].lca != -1)
		 if(!color[a[ask[i].lca]]) Ans[ask[i].num] = 1;
		Ans[ask[i].num] += ans;
		l = ask[i].l,r = ask[i].r;
	}
	for(int i = 1;i <= m;i++) printf("%d\n",Ans[i]);
}


你可能感兴趣的:(ACM,离散化,好题,离线算法)