Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 1221 Solved: 476
[Submit][Status][Discuss]
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
Sol:
非常简单的树上莫队,跑得好慢QuQ
真是受不了出题人,对0的描述不全面QuQ(还是我太sb了
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define N 50005
#define K 255
#define M 100005
inline int in(int x=0,char ch=getchar()){while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x;}
struct Q{int u,v,a,b,id;}q[M];int ut[N];
int stk[M],c[N],a[N],w[N],block[N];int n,m,cnt,Lim,top,ans;
int f[N][17],d[N];bool v[N];
inline void Add_Block(int size){cnt++;while(size--) block[stk[top--]]=cnt;}
struct Tree{
vector<int> g[N];
int dfs(int u,int p,int s=0){
for(int i=0,v,lim=g[u].size();i<lim;i++){
if((v=g[u][i])==p) continue;
f[v][0]=u,d[v]=d[u]+1,s+=dfs(v,u);
if(s>=Lim) Add_Block(s),s=0;
}return stk[++top]=u,s+1;
}
void work(){for(int i=1;i<=16;i++) for(int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];}
inline int LCA(int u,int v){
if(d[u]<d[v]) swap(u,v);int l=d[u]-d[v];
if(l) for(int i=0;i<=16;++i) if(l&(1<<i)) u=f[u][i];
if(u==v) return u;
for(int i=16;~i;--i) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
return f[u][0];
}
}t;
struct Mo{
inline void Updata(int u){
if(!v[u]&&!(c[a[u]]++)) ans++;
if(v[u]&&!(--c[a[u]])) ans--;
v[u]^=1;
}
inline void Move(int u,int v){
if(d[u]<d[v]) swap(u,v);
while(d[u]!=d[v]) Updata(u),u=f[u][0];
while(u!=v){Updata(u),u=f[u][0];Updata(v),v=f[v][0];}
}
void Solve(){
int x,y;x=y=1;ans=0;
for(int i=1;i<=m;i++){
Move(x,q[i].u),x=q[i].u,Move(y,q[i].v),y=q[i].v;
int lca=t.LCA(x,y);
if(lca) Updata(lca);
ut[q[i].id]=ans-(q[i].a!=q[i].b&&c[q[i].a]&&c[q[i].b]);
if(lca) Updata(lca);
}
}
}W;
int cmp(Q a,Q b){return block[a.u]<block[b.u]||(block[a.u]==block[b.u]&&block[a.v]<block[b.v]);}
void init(){
n=in(),m=in();int u,v;for(int i=1;i<=n;i++) a[i]=in();Lim=max(1,(int)sqrt(n*2+0.5));
for(int i=1;i<=n;i++){
u=in(),v=in();if(u&&v) t.g[u].push_back(v),t.g[v].push_back(u);
}
f[1][0]=1;t.dfs(1,1);t.work();
for(int i=1;i<=m;i++){
q[i].u=in(),q[i].v=in(),q[i].a=in(),q[i].b=in(),q[i].id=i;
if(block[q[i].u]>block[q[i].v]) swap(q[i].u,q[i].v);}
sort(q+1,q+m+1,cmp);W.Solve();
for(int i=1;i<=m;i++) printf("%d\n",ut[i]);
}
int main(){init();return 0;}