BZOJ3757 苹果树——树上莫队

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

拉成dfs序。观察dfs序发现,u->v(u比v先访问)路径上的点在dfs序的sec[u]~fir[v]中只出现一次。。。然后就又乱搞。

 

第二次更新:说的好像很不清楚呀!dfs序之后fir[x]->fir[y]包含了整棵x的子树,而我们想要查询的是路径问题,然而我们又发现,我们想要的x->y路径上的点都只会在dfs序中出现一次(我们把dfs拉成2*n),而无关点包括进出共两次,所以满足异或的性质,在序列中移指针的时候维护一个vis[x]数组就可以了,详见代码

#include
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
const int N = 5e4+10,Maxc = 1e6+10;
int n,m,c[N];
int cnt,dep[N],fir[N],sec[N],rp[N<<1];
int bl[N<<1];
struct Query{
	int L,r,p,A,b,idx;
}q[N<<1];
bool cmp(const Query&A,const Query&b){
	if(bl[A.L]^bl[b.L])return A.Lb.r;
}
struct LCA{
	vectorG[N];
	int p[N][17];
	inline void init(){
		scanf("%d%d",&n,&m);
		Inc(i,1,n)scanf("%d",&c[i]);
		Inc(i,1,n){
			int x,y;scanf("%d%d",&x,&y);
			G[x].push_back(y);
			G[y].push_back(x);
		}
	}
	inline void dfs(int x,int fa,int depth){
		rp[fir[x]=++cnt]=x;
		Inc(i,0,G[x].size()-1)if(G[x][i]^fa){
			dfs(G[x][i],p[G[x][i]][0]=x,dep[G[x][i]]=depth+1);
		}
		rp[sec[x]=++cnt]=x;
	}
	inline void ST(){
		memset(p,-1,sizeof(p));
		dfs(0,0,0);
		int maxdep=log2(n);
		Inc(j,1,maxdep)
			Inc(i,1,n)if(~p[i][j-1])p[i][j]=p[p[i][j-1]][j-1];
	}
	inline int lca(int x,int y){
		if(dep[x]=dep[y])x=p[x][i];
		if(x==y)return y;
		Red(i,log2(dep[x]),0)
			if(p[x][i]^p[y][i])x=p[x][i],y=p[y][i];
		return p[x][0];
	}
}g;
struct MOTO{
	inline void init(){
		Inc(i,1,m){
			int x,y,A,b;scanf("%d%d%d%d",&x,&y,&A,&b);
			if(fir[x]>fir[y])swap(x,y);
			int p=g.lca(x,y);
			if(x==p)q[i]=(Query){fir[x],fir[y],0,A,b,i};
			else q[i]=(Query){sec[x],fir[y],p,A,b,i};
		}
	}
	int tmp,ans[N<<1],doc[Maxc];
	bool vst[N];
	inline void addr(int x){
		if(vst[x]){
			if(--doc[c[x]]==0)--tmp;
		}else {
			if(++doc[c[x]]==1)++tmp;
		}
		vst[x]^=1;
	}
	inline void solv(){
		int siz=sqrt(n<<1);
		Inc(i,1,n<<1)bl[i]=(i-1)/siz+1;
		sort(q+1,q+m+1,cmp);
		int L=1,r=0;
		Inc(i,1,m){
			while(L>q[i].L)addr(rp[--L]);
			while(Lq[i].r)addr(rp[r--]);
			if(q[i].p)addr(q[i].p);
			ans[q[i].idx]=tmp;
			if(doc[q[i].A]&&doc[q[i].b]&&(q[i].A^q[i].b))--ans[q[i].idx];
			if(q[i].p)addr(q[i].p);
		}
		Inc(i,1,m)cout<

 

你可能感兴趣的:(莫队,离线)