神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个到n之间的正整数来表示一种颜色。树上一共有n个苹果。每个苹果都被编了号码,号码为一个1到n之间的正整数。我们用0代表树根。只会有一个苹果直接根。
有许许多多的人来神犇家里膜拜神犇。可神犇可不是随便就能膜拜的。前来膜拜神犇的人需要正确回答一个问题,才能进屋膜拜神犇。这个问题就是,从树上编号为u的苹果出发,由树枝走到编号为v的苹果,路径上经过的苹果一共有多少种不同的颜色(包括苹果u和苹果v的颜色)?不过神犇注意到,有些来膜拜的人患有色盲症。具体地说,一个人可能会认为颜色a就是颜色b,那么他们在数苹果的颜色时,如果既出现了颜色a的苹果,又出现了颜色b的苹果,这个人只会算入颜色b,而不会把颜色a算进来。
神犇是一个好人,他不会强人所难,也就会接受由于色盲症导致的答案错误(当然答案在色盲环境下也必须是正确的)。不过这样神犇也就要更改他原先数颜色的程序了。虽然这对于神犇来说是小菜一碟,但是他想考验一下你。你能替神犇完成这项任务吗?
Input
输入第一行为两个整数n和m,分别代表树上苹果的个数和前来膜拜的人数。
接下来的一行包含n个数,第i个数代表编号为i的苹果的颜色Coli。
接下来有n行,每行包含两个数x和y,代表有一根树枝连接了苹果x和y(或者根和一个苹果)。
接下来有m行,每行包含四个整数u、v、a和b,代表这个人要数苹果u到苹果v的颜色种数,同时这个人认为颜色a就是颜色b。如果a=b=0,则代表这个人没有患色盲症。
Output
输出一共m行,每行仅包含一个整数,代表这个人应该数出的颜色种数。
Sample Input
5 3
1 1 3 3 2
0 1
1 2
1 3
2 4
3 5
1 4 0 0
1 4 1 3
1 4 1 2
Sample Output
2
1
2
HINT
0<=x,y,a,b<=N
N<=50000
1<=U,V,Coli<=N
树上莫队,可参照这篇不错的博客
#include <queue> #include <cmath> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; template<typename T> void read(T &x){ x = 0;char ch = getchar();int f = 1; while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();} while(isdigit(ch)){x = x*10+ch-48;ch=getchar();} x*=f; } const int N = 100050; int n,m,va[N],u,v,tim = 0,dfn[N],depth[N],fff[N][16],buc[N] = {0},taken[N] = {0},ans = 0,blc,rans[N]; vector<int> G[N]; void dfs(int num,int fa = -1){ tim++; dfn[num] = tim; fff[num][0] = fa; for(int i=1;i<=15;i++)fff[num][i] = fff[fff[num][i-1]][i-1]; for(int i=0;i<G[num].size();i++){ int ct = G[num][i]; if(ct == fa)continue; depth[ct] = depth[num]+1; dfs(ct,num); } } int lca(int u,int v){ if(depth[u]<depth[v])swap(u,v); for(int i=15;i>=0;i--)if(fff[u][i]!=-1 && depth[fff[u][i]] >=depth[v])u = fff[u][i]; for(int i=15;i>=0;i--)if(fff[u][i]!=-1&&fff[v][i]!=-1&&fff[u][i]!=fff[v][i])u=fff[u][i],v=fff[v][i]; if(u == v)return u; return fff[u][0]; } struct query{ int l,r,a,b,id; bool operator < (const query &rhs) const{ if(dfn[l]/blc!=dfn[rhs.l]/blc) return dfn[l]/blc<dfn[rhs.l]/blc; return dfn[r]<dfn[rhs.r]; } }Q[N]; inline void chg(int x){ if(taken[x]){ if(buc[va[x]] == 1)ans--; buc[va[x]]--; taken[x] = 0; }else{ if(buc[va[x]] == 0)ans++; buc[va[x]]++; taken[x] = 1; } } void mov(int u,int v){ if(depth[u]<depth[v])swap(u,v); while(depth[u]>depth[v]){ chg(u); u = fff[u][0]; } while(u!=v){ chg(u);chg(v); u = fff[u][0]; v = fff[v][0]; } } int main() { read(n);read(m); blc = sqrt(n)+1; for(int i=1;i<=n;i++)read(va[i]); for(int i=1;i<=n;i++){ read(u);read(v); G[u].push_back(v); G[v].push_back(u); } depth[0] = 0; dfs(0); for(int i=0;i<m;i++){ read(Q[i].l);read(Q[i].r);read(Q[i].a);read(Q[i].b);Q[i].id = i; if(dfn[Q[i].l]>dfn[Q[i].r])swap(Q[i].l,Q[i].r); } sort(Q,Q+m); int ccl = 0,ccr = 0; for(int i=0;i<m;i++){ int cl = Q[i].l,cr = Q[i].r; mov(ccl,cl); mov(ccr,cr); ccl = cl;ccr = cr; cl = lca(ccl,ccr); chg(cl); rans[Q[i].id] = ans-(Q[i].a!=Q[i].b&&buc[Q[i].a] && buc[Q[i].b]); chg(cl); } for(int i=0;i<m;i++)cout<<rans[i]<<'\n'; return 0; }
发表回复