Description
神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个到n之间的正整数来表示一种颜色。树上一共有n个苹果。每个苹果都被编了号码,号码为一个1到n之间的正整数。我们用0代表树根。只会有一个苹果直接根。
有许许多多的人来神犇家里膜拜神犇。可神犇可不是随便就能膜拜的。前来膜拜神犇的人需要正确回答一个问题,才能进屋膜拜神犇。这个问题就是,从树上编号为u的苹果出发,由树枝走到编号为v的苹果,路径上经过的苹果一共有多少种不同的颜色(包括苹果u和苹果v的颜色)?不过神犇注意到,有些来膜拜的人患有色盲症。具体地说,一个人可能会认为颜色a就是颜色b,那么他们在数苹果的颜色时,如果既出现了颜色a的苹果,又出现了颜色b的苹果,这个人只会算入颜色b,而不会把颜色a算进来。
神犇是一个好人,他不会强人所难,也就会接受由于色盲症导致的答案错误(当然答案在色盲环境下也必须是正确的)。不过这样神犇也就要更改他原先数颜色的程序了。虽然这对于神犇来说是小菜一碟,但是他想考验一下你。你能替神犇完成这项任务吗?
Input
Output
输出一共m行,每行仅包含一个整数,代表这个人应该数出的颜色种数。
Sample Input
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
1
2
HINT
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~树上莫队~
和上一道差不多,就是要求一下root的位置,不能直接用1来代替。
BZOJ上不能测,要了数据测的~
fa[i][j]数组又开小了……调到吐血tat
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,a[50005],fi[100005],w[100005],ne[100005],cnt,stk[100005],top,totcas,fa[100005][18],dep[100005];
int pos[100005],num[100005],ans[100005],now,kkz,dfn[100005],jin,root;
bool b[100005];
struct node{
int x,y,a,b,id;
}que[100001];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
void add(int u,int v)
{
w[++cnt]=v;ne[cnt]=fi[u];fi[u]=cnt;
w[++cnt]=u;ne[cnt]=fi[v];fi[v]=cnt;
}
void dfs(int u)
{
dfn[u]=++kkz;
for(int i=1;(1<<i)<=dep[u];i++) fa[u][i]=fa[fa[u][i-1]][i-1];
int now=top;
for(int i=fi[u];i;i=ne[i])
if(w[i]!=fa[u][0])
{
fa[w[i]][0]=u;dep[w[i]]=dep[u]+1;
dfs(w[i]);
if(top-now>=jin)
{
totcas++;
while(top-now>=jin) pos[stk[top--]]=totcas;
}
}
stk[++top]=u;
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int now=dep[u]-dep[v];
for(int i=0;(1<<i)<=now;i++) if((1<<i)&now) u=fa[u][i];
if(u==v) return u;
for(int i=17;~i;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
bool operator < (node u,node v)
{
return pos[u.x]==pos[v.x] ? dfn[u.y]<dfn[v.y]:pos[u.x]<pos[v.x];
}
void xo(int u)
{
if(b[u]) now-=((--num[a[u]])==0);
else now+=((++num[a[u]])==1);
b[u]^=1;
}
void chan(int u,int v)
{
while(u!=v)
if(dep[u]>dep[v]) xo(u),u=fa[u][0];
else xo(v),v=fa[v][0];
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++)
{
int x=read(),y=read();
if(!(x*y)) root=x+y;
else add(x,y);
}
jin=sqrt(n);dfs(root);
while(top) pos[stk[top--]]=totcas;
for(int i=1;i<=m;i++)
{
que[i].x=read();que[i].y=read();que[i].a=read();que[i].b=read();que[i].id=i;
if(pos[que[i].x]>pos[que[i].y]) swap(que[i].x,que[i].y);
}
sort(que+1,que+m+1);
int x=root,y=root,k;
for(int i=1;i<=m;i++)
{
if(x!=que[i].x) chan(x,que[i].x),x=que[i].x;
if(y!=que[i].y) chan(y,que[i].y),y=que[i].y;
k=lca(x,y);xo(k);
if(que[i].a==que[i].b || !(num[que[i].a]*num[que[i].b])) ans[que[i].id]=now;
else ans[que[i].id]=now-1;xo(k);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}