BZOJ 3757 苹果树

来源:互联网 发布:淘宝上的佳德凤梨酥 编辑:程序博客网 时间:2024/06/02 02:03

Description

    神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个到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

M<=100000

此题存在版权,故不再支持提交,保留在此只供大家参考题面! 望见谅!

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;}


1 0