Time:2016.09.07
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
第一次写树上莫队
被char哥怒裱一通
实际上还是比较简单的
序列的相关维护问题转移到树上一般都要涉及到dfs序
一开始学的时候被恶心了很久,因为去的是盗贴网站,markdown语法都是错误的= =
如果大家要学的话去百度一下就找到了,讲的还是很良心的
核心思想就是(u,v)到(u,v’)的转化只需要走(v,v’)就可以了
还有就是LCA的问题
我这里用的是ST表求LCA
数组可能比较多,看起来稍微有些乱
我就是来写个博文签个到
简直就是差评博文!!
跑的还是挺快的,好像是rank6,不知道有没有被刷下来
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 40005
#define M 100005
using namespace std;
int n,m,tot,S;
int a[N],b[N],block[N],first[N],sum[N],ans[M],dfn[N],fa[N<<1][17],pos[N],num[N<<1],dep[N],F[N];
//dfn表示dfs序序号,sum是每种颜色的个数,fa是ST表,F是每个点的父亲,num存dfs顺序,pos存每个点第一次出现在num中的位置,b用于离散化
bool vis[N];
struct edge{
int v,next;
}e[N<<1];
struct node{
int l,r,id;
}q[M];
int in()
{
int t=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
int cmp(node a,node b)
{
if (block[a.l]==block[b.l]) return dfn[a.r]<dfn[b.r];
return block[a.l]<block[b.l];
}
void add(int x,int y)
{
e[++tot]=(edge){y,first[x]};first[x]=tot;
e[++tot]=(edge){x,first[y]};first[y]=tot;
}
void dfs(int x,int f)
{
dfn[x]=++dfn[0];
num[++num[0]]=x;
fa[num[0]][0]=x;
pos[x]=num[0];
for (int i=first[x];i;i=e[i].next)
if (e[i].v!=f)
dep[e[i].v]=dep[x]+1,
F[e[i].v]=x,
dfs(e[i].v,x),
num[++num[0]]=x,
fa[num[0]][0]=x;
}
int LCA(int x,int y)
{
x=pos[x];y=pos[y];
if (x>y) swap(x,y);
int p=log2(y-x+1);
if (dep[fa[x][p]]>dep[fa[y-(1<<p)+1][p]])
return fa[y-(1<<p)+1][p];
else
return fa[x][p];
}
void Point(int x)
{
if (vis[x]) S-=(--sum[a[x]]==0);
else S+=(++sum[a[x]]==1);
vis[x]^=1;
}
void Path(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (;dep[x]!=dep[y];x=F[x])
Point(x);
for (;x!=y;x=F[x],y=F[y])
Point(x),Point(y);
}
main()
{
n=in();m=in();
for (int i=1;i<=n;++i) a[i]=b[i]=in();
sort(b+1,b+n+1);
b[0]=unique(b+1,b+1+n)-b-1;
for (int i=1;i<=n;++i)
a[i]=lower_bound(b+1,b+b[0]+1,a[i])-b;
for (int i=1;i<n;++i)
add(in(),in());
dfs(1,0);
for (int i=1;1<<i<=num[0];++i)
for (int j=1;j+(1<<i)-1<=num[0];++j)
if (dep[fa[j][i-1]]>dep[fa[j+(1<<i-1)][i-1]])
fa[j][i]=fa[j+(1<<i-1)][i-1];
else
fa[j][i]=fa[j][i-1];
int tt=sqrt(n);
for (int i=1;i<=n;++i)
block[i]=(dfn[i]-1)/tt+1;
for (int i=1;i<=m;++i)
{
q[i]=(node){in(),in(),i};
if (dfn[q[i].l]>dfn[q[i].r]) swap(q[i].l,q[i].r);
}
sort(q+1,q+m+1,cmp);
int L=1,R=1;Point(1);
for (int i=1;i<=m;++i)
{
Path(L,q[i].l);
Path(R,q[i].r);
Point(LCA(L,R));
Point(LCA(q[i].l,q[i].r));
ans[q[i].id]=S;
L=q[i].l;R=q[i].r;
}
for (int i=1;i<=m;++i) printf("%d\n",ans[i]);
}