原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3757
苹果树
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
题解
树上莫队模板。
算法介绍的话,写在莫队总结里好了,题解就这样吧。。。
代码
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int M=1e5+5;
struct sd{int f,t,a,b,id;};
sd ask[M];
bool vis[M];
int col[M],team[M],n,m,siz[M],dad[M],dep[M],son[M],top[M],sta[M],id[M],tot,zhan,big,num,ans[M],root,cot[M],hh;
bool operator <(sd a,sd b){return team[a.f]==team[b.f]?id[a.t]<id[b.t]:team[a.f]<team[b.f];}
vector<int>mmp[M];
void in()
{
int a,b;R i;
scanf("%d%d",&n,&m);big=(int)pow(n,6.0/10.0);
for(i=1;i<=n;++i)scanf("%d",&col[i]);
for(i=1;i<=n;++i){scanf("%d%d",&a,&b),mmp[a].push_back(b),mmp[b].push_back(a);if(!a||!b)root=a?a:b;}
}
int dfs1(int v,int f,int d)
{
id[v]=++tot;dad[v]=f;siz[v]=1;dep[v]=d;
int bs=0,to,tmp,now=zhan;
for(int i=mmp[v].size()-1;i>=0;--i)
{
to=mmp[v][i];if(to==f)continue;tmp=dfs1(to,v,d+1);
if(tmp>bs)son[v]=to,bs=tmp;
siz[v]+=tmp;
if(zhan-now>=big){++num;while(zhan!=now)team[sta[zhan--]]=num;}
}
sta[++zhan]=v;
return siz[v];
}
void dfs2(int v,int t)
{
top[v]=t;int to;
if(son[v])dfs2(son[v],t);
for(int i=mmp[v].size()-1;i>=0;--i){to=mmp[v][i];if(to==dad[v]||to==son[v])continue;dfs2(to,to);}
}
int lca(int x,int y)
{
while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=dad[top[x]];}
return dep[x]<dep[y]?x:y;
}
void rev(int x){if(vis[x]&&--cot[col[x]]==0)hh--;if(!vis[x]&&++cot[col[x]]==1)hh++;vis[x]^=1;}
void walk(int x,int y){while(x!=y){if(dep[x]<dep[y])swap(x,y);rev(x);x=dad[x];}}
void ac()
{
R i;dfs1(root,0,1);dfs2(root,root);
if(zhan){num++;while(zhan){team[sta[zhan--]]=num;}}
for(i=1;i<=m;++i)
{
scanf("%d%d%d%d",&ask[i].f,&ask[i].t,&ask[i].a,&ask[i].b),ask[i].id=i;
if(id[ask[i].f]>id[ask[i].t])swap(ask[i].f,ask[i].t);
}
sort(ask+1,ask+1+m);
int F=1,T=1,lc,p;
for(i=1;i<=m;++i)
{
walk(F,ask[i].f);walk(T,ask[i].t);F=ask[i].f,T=ask[i].t;lc=lca(F,T);rev(lc);p=0;
if(ask[i].a!=ask[i].b&&cot[ask[i].a]&&cot[ask[i].b])p=1;
ans[ask[i].id]=hh-p;rev(lc);
}
for(i=1;i<=m;++i)
printf("%d\n",ans[i]);
}
int main()
{
in();ac();
return 0;
}