树上莫队跟线性莫队是一个性质的
首先将树分块,对于每个查询[u,v],优先级为
bool operator < (const point &rhs) const
{
return belong[u] < belong[rhs.u] || (belong[u] == belong[rhs.u] && pre[v] < pre[rhs.v]);
}
转移的话,具体操作就是使用反转,详见
http://vfleaking.blog.163.com/blog/static/174807634201311011201627/
也就没啥了~
#include <cstdio>
#include <vector>
#include <cmath>
#include <stack>
#include <algorithm>
using namespace std;
const int MAXN = 200001;
const int MAXM = 200001;
const int MAXSTEP = 21;
void read(int &x)
{
x = 0;
char c;
do c = getchar();while (c < '0' || c > '9');
do x = x*10+c-48, c = getchar();while (c >= '0' && c <= '9');
}
int n,m,dfs_clock,block_size,cnt_block,now_ans;
int belong[MAXN],pre[MAXN];
struct point
{
int u,v,id;
bool operator < (const point &rhs) const
{
return belong[u] < belong[rhs.u] || (belong[u] == belong[rhs.u] && pre[v] < pre[rhs.v]);
}
};
struct Node
{
int color,id;
bool operator < (const Node &rhs) const
{
return color < rhs.color;
}
};
point P[MAXM];
Node data[MAXN];
int color[MAXN],pos[MAXN],deep[MAXN];
int f[MAXN][MAXSTEP+5];
int num[MAXN],ans[MAXN];
bool vis[MAXN];
vector <int> G[MAXN];
stack <int> S;
int dfs(int u,int fa,int dep)
{
S.push(u);
int size = 0;
pre[u] = ++dfs_clock;
f[u][0] = fa;
deep[u] = dep;
for (int i=0;i<G[u].size();i++) if (!pre[G[u][i]])
{
size += dfs(G[u][i],u,dep+1);
if (size > block_size)
{
cnt_block++;
for (int j=1;j<=size;j++)
{
int x = S.top();
S.pop();
belong[x] = cnt_block;
}
size = 0;
}
}
return size+1;
}
void prepare()
{
//未完成序列
cnt_block++;
while (!S.empty())
{
int x = S.top();
S.pop();
belong[x] = cnt_block;
}
for (int i=1;i<MAXSTEP;i++)
for (int j=1;j<=n;j++) f[j][i] = f[f[j][i-1]][i-1];
}
int lca(int u,int v)
{
if (deep[u] > deep[v]) swap(u,v);
int delta_h = deep[v]-deep[u];
for (int i=0;i<MAXSTEP;i++) if (delta_h & (1 << i)) v = f[v][i];
if (u == v) return u;
for (int i=MAXSTEP;i>0;i--) if (f[u][i] != f[v][i])
{
u = f[u][i];
v = f[v][i];
}
return f[u][0];
}
void reverse(int u)
{
if (!vis[u])
{
vis[u] = true, num[pos[u]]++;
if (num[pos[u]] == 1) now_ans++;
}
else
{
vis[u] = false, num[pos[u]]--;
if (num[pos[u]] == 0) now_ans--;
}
}
void solve(int u,int v)
{
while (u != v)
if (deep[u] > deep[v]) reverse(u),u = f[u][0];
else reverse(v),v = f[v][0];
}
int main()
{
freopen("test.in","r",stdin);
read(n);read(m);
for (int i=1;i<=n;i++) read(data[i].color),data[i].id = i;
sort(data+1,data+n+1);
int now_point = 0;
for (int i=1;i<=n;i++)
{
now_point++;
if (data[i].color == data[i-1].color) now_point--;
pos[data[i].id] = now_point;
}
for (int i=1;i<n;i++)
{
int u,v;
read(u);read(v);
G[u].push_back(v);
G[v].push_back(u);
}
block_size = ceil(sqrt(n));
dfs(1,0,1);
prepare();
for (int i=1;i<=m;i++)
{
read(P[i].u),read(P[i].v);
P[i].id = i;
if (pre[P[i].u] > pre[P[i].v]) swap(P[i].u,P[i].v);
}
sort(P+1,P+m+1);
int tp = lca(P[1].u,P[1].v);
solve(P[1].u,P[1].v);
reverse(tp);
ans[P[1].id] = now_ans;
for (int i=2;i<=m;i++)
{
solve(P[i].u,P[i-1].u);
solve(P[i].v,P[i-1].v);
ans[P[i].id] = now_ans;
}
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}