学习笔记:tarjan求lca

今天学了一下tarjan求lca(离线的),时间复杂度为O(n*a(n)),就是并查集的时间复杂度。

对于一个询问(u,v),我们先把它加进u开头的与v开头的邻接链表。然后做一遍Dfs。我们肯定会先Dfs到其中一个节点(假设是u),在Dfs到另外一个(v)。那么我们在Dfs到u的时候,把vis[u]标为true,然后在Dfs到v的时候,我们处理所有vis为true的v的邻接链表中的u。它们的lca便为当前的fa[u](这个很容易证明)。在做一个节点的时候,先Dfs它的子树,把它子节点的fa标记为它,然后把它自己标记为true,最后处理它的邻接链表。

我这个写得很简略(给自己复习用的)。这里有个blog写得不错,真心推荐一下(我当初就是看这个会的):

http://www.mamicode.com/info-detail-1067269.html

当然啦,学了之后把它套在了running(Noip2016 Day2 T2)的树剖做法上面,把原先那个垃圾的倍增求lca踢掉了。然而还是超一个点……(还是用树上差分好)

CODE:

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn=300100;
const int maxl=19;

struct data
{
	int obj,_Next;
} e[maxn<<1];
int head[maxn];
int cur=-1;

struct data1
{
	int id,val,num,_Next1;
} e1[maxn*maxl<<2];
int head1[maxn];
int cur1=-1;

int fa[maxn][maxl];
int dep[maxn];

int _Size[maxn];
int _Son[maxn];

int w[maxn];
int _Time;
int dfsx[maxn];
int top[maxn];

int que[maxn];
int he=0,ta=1;

int A[maxn];
int B[maxn];

int cntA[maxn];
int cntB[maxn<<1];

struct data2
{
	int obj2,id2,_Next2;
} e2[maxn<<1];
int head2[maxn];
int cur2=-1;

int father[maxn];
bool vis[maxn];

struct data3
{
	int nu,nv,nlca;
} ask[maxn];

int ans[maxn];

int n,m;

void Add(int x,int y)
{
	cur++;
	e[cur].obj=y;
	e[cur]._Next=head[x];
	head[x]=cur;
}

void Bfs1()
{
	que[1]=1;
	fa[1][0]=1;
	dep[1]=1;
	while (he=2; i--)
	{
		int son=que[i];
		int node=fa[son][0];
		_Size[node]+=_Size[son];
		if (_Size[son]>_Size[ _Son[node] ])
			_Son[node]=son;
	}
}

void Bfs3()
{
	top[1]=1;
	w[1]=1;
	dfsx[1]=1;
	for (int i=1; iw[v]) swap(u,v);
		Add1(w[u],nid,nval,1);
		Add1(w[v]+1,nid,nval,-1);
		return;
	}
	if (dep[ top[u] ]


你可能感兴趣的:(Lca)