树上莫队 COT2

        树上莫队跟线性莫队是一个性质的

        首先将树分块,对于每个查询[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;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值