神犇家門口種了一棵蘋果樹。蘋果樹做爲一棵樹,固然是呈樹狀結構,每根樹枝鏈接兩個蘋果,每一個蘋果均可以沿着一條由樹枝構成的路徑連到樹根,並且這樣的路徑只存在一條。因爲這棵蘋果樹是神犇種的,因此蘋果都發生了變異,變成了各類各樣的顏色。咱們用一個到n之間的正整數來表示一種顏色。樹上一共有n個蘋果。每一個蘋果都被編了號碼,號碼爲一個1到n之間的正整數。咱們用0表明樹根。只會有一個蘋果直接根。c++
有許許多多的人來神犇家裏膜拜神犇。可神犇可不是隨便就能膜拜的。前來膜拜神犇的人須要正確回答一個問題,才能進屋膜拜神犇。這個問題就是,從樹上編號爲u的蘋果出發,由樹枝走到編號爲v的蘋果,路徑上通過的蘋果一共有多少種不一樣的顏色(包括蘋果u和蘋果v的顏色)?不過神犇注意到,有些來膜拜的人患有色盲症。具體地說,一我的可能會認爲顏色a就是顏色b,那麼他們在數蘋果的顏色時,若是既出現了顏色a的蘋果,又出現了顏色b的蘋果,這我的只會算入顏色b,而不會把顏色a算進來。spa
神犇是一個好人,他不會強人所難,也就會接受因爲色盲症致使的答案錯誤(固然答案在色盲環境下也必須是正確的)。不過這樣神犇也就要更改他原先數顏色的程序了。雖然這對於神犇來講是小菜一碟,可是他想考驗一下你。你能替神犇完成這項任務嗎?code
輸入第一行爲兩個整數n和m,分別表明樹上蘋果的個數和前來膜拜的人數。ip
接下來的一行包含n個數,第i個數表明編號爲i的蘋果的顏色Coli。input
接下來有n行,每行包含兩個數x和y,表明有一根樹枝鏈接了蘋果x和y(或者根和一個蘋果)。it
接下來有m行,每行包含四個整數u、v、a和b,表明這我的要數蘋果u到蘋果v的顏色種數,同時這我的認爲顏色a就是顏色b。若是a=b=0,則表明這我的沒有患色盲症。io
輸出一共m行,每行僅包含一個整數,表明這我的應該數出的顏色種數。class
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程序
2
1
2im
0<=x,y,a,b<=N
N<=50000
1<=U,V,Coli<=N
M<=100000
樹上莫隊板子
直接網上搜樹上莫隊就能夠了
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int n, m, cur = 0; int top = 0, ind = 0, blosiz, blonum, root; int res[N], p[N]; int fa[N][20], dep[N]; int c[N], st[N], dfn[N], bel[N]; bool vis[N]; struct Edge { int v, nxt; } E[N]; int head[N], cnt = 0; struct Query { int u, v, a, b, id; } q[N]; bool operator < (const Query &a, const Query &b) { return bel[a.u] == bel[b.u] ? dfn[a.v] < dfn[b.v] : bel[a.u] < bel[b.u]; } void addedge(int u, int v) { E[++cnt] = (Edge) {v, head[u]}; head[u] = cnt; } int dfs(int u) { int siz = 0; dfn[u] = ++ind; for (int i = 1; i <= 18; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int i = head[u]; i; i = E[i].nxt) { int v = E[i].v; if (v == fa[u][0]) continue; dep[v] = dep[u] + 1; fa[v][0] = u; siz += dfs(v); if (siz >= blosiz) { ++blonum; for (int k = 1; k <= siz; k++) { bel[st[top--]] = blonum; } siz = 0; } } st[++top] = u; return siz + 1; } int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); int delta = dep[x] - dep[y]; for (int i = 0; i <= 18; i++) { if ((delta >> i) & 1) { x = fa[x][i]; } } if (x == y) return x; for (int i = 18; i >= 0; i--) { if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; } void reverse(int x) { if (!vis[x]) { vis[x] = 1; if (++p[c[x]] == 1) ++cur; } else { vis[x] = 0; if (--p[c[x]] == 0) --cur; } } void solve(int u, int v) { while (u != v) { if (dep[u] > dep[v]) { reverse(u); u = fa[u][0]; } else { reverse(v); v = fa[v][0]; } } } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif scanf("%d %d", &n, &m); blosiz = sqrt(n << 1); for (int i = 1; i <= n; i++) scanf("%d", &c[i]); for (int i = 1; i <= n; i++) { int u, v; scanf("%d %d", &u, &v); if (!u) root = v; if (!v) root = u; if (u && v) { addedge(u, v); addedge(v, u); } } dfs(root); if (top) { blonum++; while (top) { bel[st[top--]] = blonum; } } for (int i = 1; i <= m; i++) { scanf("%d %d %d %d", &q[i].u, &q[i].v, &q[i].a, &q[i].b); if (dfn[q[i].u] > dfn[q[i].v]) swap(q[i].u, q[i].v); q[i].id = i; } sort(q + 1, q + m + 1); int t = lca(q[1].u, q[1].v); solve(q[1].u, q[1].v); reverse(t); res[q[1].id] = cur - (p[q[1].a] && p[q[1].b] && q[1].a != q[1].b); reverse(t); for (int i = 2; i <= m; i++) { solve(q[i - 1].u, q[i].u); solve(q[i - 1].v, q[i].v); t = lca(q[i].u, q[i].v); reverse(t); res[q[i].id] = cur - (p[q[i].a] && p[q[i].b] && q[i].a != q[i].b); reverse(t); } for (int i = 1; i <= m; i++) printf("%d\n", res[i]); return 0; }