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 (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.
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: 44
题意:给一棵染过色的数,每个点有一个颜色,每次询问树上一段路径的颜色数量。
分析: 树上莫队,通过dfs序可以把树上的一段路径转换为一段序列,剩下做法就和一般的序列莫队一样了。
#include <cstdio> #include <iostream> #include <vector> #include <algorithm> #include <cmath> #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<int> 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<<j) <= n;j++) for(int i = 1;i <= n;i++) f[i][j] = f[f[i][j-1]][j-1]; } int LCA(int u,int v) { if(deep[u] < deep[v]) swap(u,v); int d = deep[u] - deep[v]; for(int i = 0;i < 30;i++) if((1<<i) & d) u = f[u][i]; if(u == v) return u; for(int i = 29;i >= 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]); }