【BZOJ1086】【SCOI2005】王室联邦
【BZOJ3052】【WC2013】糖果公园

【BZOJ3757】苹果树

Zarxdy34 posted @ 2016年3月06日 19:29 in BZOJ with tags 树上莫队 , 738 阅读

  树上莫队的模板题。前置技能BZOJ1086的树分块,然后和序列上的莫队差不多的做法。询问按第一关键字为左端点所在块,第二关键字为右端点的DFS序排序。

  维护当前路径上有哪些点的时候不记录两端点的公共祖先,这样操作比较好。

  另外对每个从u到v的询问,如果u所在块大于v所在块就交换u和v。

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=50010,maxm=100010;

void read(int &x) {char ch;while ((ch=getchar())<'0' || ch>'9');x=ch-'0';while ((ch=getchar())<='9' && ch>='0') x=x*10+ch-'0';}

struct Query {int u,v,a,b,block,id;}Q[maxm];

int head[maxn],next[maxn<<1],E[maxn<<1],Ecnt;
int Col[maxn];
int n,m,V;

void Add_Edge(int x,int y) {next[++Ecnt]=head[x];head[x]=Ecnt;E[Ecnt]=y;next[++Ecnt]=head[y];head[y]=Ecnt;E[Ecnt]=x;}

int DFSID[maxn],IDs;
int belong[maxn],Bcnt;
int fa[maxn][20],dep[maxn];
int stack[maxn],top;
void DFS(int x,int father,int depth)
{
	int bottom=top;
	dep[x]=depth;
	fa[x][0]=father;
	for (int l=0;fa[fa[x][l]][l];l++) fa[x][l+1]=fa[fa[x][l]][l];
	DFSID[x]=++IDs;
	for (int i=head[x];i;i=next[i]) if (E[i]!=father)
	{
		DFS(E[i],x,depth+1);
		if (top-bottom>=V)
		{
			++Bcnt;
			while (top>bottom) belong[stack[top--]]=Bcnt;
		}
	}
	stack[++top]=x;
}

void Init()
{
	read(n),read(m);
	while (V*V<n) V++;
	for (int i=1;i<=n;i++) read(Col[i]);
	for (int i=1,x,y;i<=n;i++)
	{
		read(x),read(y);
		if (x&&y) Add_Edge(x,y);
	}
	DFS(1,0,1);
	Bcnt++;
	while (top) belong[stack[top--]]=Bcnt;
}

bool cmp(const Query &a,const Query &b) {return a.block<b.block || a.block==b.block && DFSID[a.v]<DFSID[b.v];}
int vis[maxn],colcnt[maxn],ans[maxm],res;

int LCA(int u,int v)
{
	if (dep[u]<dep[v]) swap(u,v);
	int l=0,dis=dep[u]-dep[v];
	while (dis)
	{
		if (dis&1) u=fa[u][l];
		dis>>=1;
		l++;
	}
	l=0;
	while (fa[u][l]!=fa[v][l]) l++;
	while (l>=0)
	{
		if (fa[u][l]!=fa[v][l]) u=fa[u][l],v=fa[v][l];
		l--;
	}
	if (u!=v) u=fa[u][0],v=fa[v][0];
	return u;
}

void Update(int u,int v)
{
	v=fa[v][0];
	while (u!=v)
	{
		if (!vis[u])
		{
			colcnt[Col[u]]++;
			if (colcnt[Col[u]]==1) res++;
			vis[u]=1;
		}
		else
		{
			colcnt[Col[u]]--;
			if (colcnt[Col[u]]==0) res--;
			vis[u]=0;
		}
		u=fa[u][0];
	}
}

void Solve()
{
	for (int i=1;i<=m;i++)
	{
		read(Q[i].u),read(Q[i].v),read(Q[i].a),read(Q[i].b),Q[i].id=i;
		if (belong[Q[i].u]>belong[Q[i].v]) swap(Q[i].u,Q[i].v);
		Q[i].block=belong[Q[i].u];
	}
	sort(Q+1,Q+1+m,cmp);
	int u=1,v=1;
	for (int i=1;i<=m;i++)
	{
		int lca=LCA(u,Q[i].u);
		Update(u,lca);
		Update(Q[i].u,lca);
		lca=LCA(v,Q[i].v);
		Update(v,lca);
		Update(Q[i].v,lca);
		u=Q[i].u;v=Q[i].v;
		lca=LCA(u,v);
		Update(lca,lca);
		if (Q[i].a==Q[i].b) ans[Q[i].id]=res;
		else if (colcnt[Q[i].a] && colcnt[Q[i].b]) ans[Q[i].id]=res-1;else ans[Q[i].id]=res;
		Update(lca,lca);
	}
	for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}

int main()
{
	Init();
	Solve();
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter