【BZOJ3732】Network,NOIP2013货车运输,ygylca

跟NOIP的题是一模一样的,我重写了一遍,这个代码更清晰一点。

思路见http://blog.csdn.net/vmurder/article/details/38734663

    但我仍要再说一遍思路。

    首先我们最小生成树建图,这个就不进行证明了,因为按照kruskal建图的话,每遍历过一条边,就相当于有一些询问间有了道路,而且一定是该边。

    然后就是ygylca了。思想:把要处理的东西扔到该节点,按一定顺序在该节点处理,并且处理后扔到lca,然后因为到了lca处时有些需要顺序处理的信息已经处理完了,所以可以在这里处理像处理的信息。

    比如本题就是两点到lca的路径中的最长边较大值。

    这个树边类题思想的时间复杂度很优秀哦!而且思路远比树剖清晰,比较好写,但是只能离线,即使做在线也是用一些跟时间戳有关的方法将在线转换成离线做。


中间的TLE是另一种没深想的思想,可能可以优化,读者可以看看。

直接看代码,然后手模拟就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 101000
using namespace std;
struct KSD
{
	int u,v,next,note,len;
	bool operator < (const KSD &a)const
	{return len<a.len;}
}e[N],eq[N],elca[N],road[N];
int head[N],headq[N],headlca[N];
int cnt,cntq,cntlca;
void add(int u,int v,int len)
{
	++cnt;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].len=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}
void addq(int u,int v)
{
	++cntq;
	eq[cntq].u=u;
	eq[cntq].v=v;
	eq[cntq].next=headq[u];
	headq[u]=cntq;
}
void addlca(int u,int v,int lca,int note)
{
	++cntlca;
	elca[cntlca].u=u;
	elca[cntlca].v=v;
	elca[cntlca].next=headlca[lca];
	elca[cntlca].note=note;
	headlca[lca]=cntlca;
}

int n,m,p;
int f[N],l[N],visit[N],vis[N],ans[N];

int find(int x)
{
	int t=f[x];
	if(f[x]==x)return x;
	f[x]=find(f[x]);
	l[x]=max(l[x],l[t]);
	return f[x];
}

void ygylca(int x,int p,int len)
{
	int i,u,v,fa,fb;
	for(i=head[x];i;i=e[i].next)
	{
		v=e[i].v;
		if(v==p)continue;
		ygylca(v,x,e[i].len);
	}
	for(i=headq[x];i;i=eq[i].next)
	{
		v=eq[i].v;
		if(visit[v])addlca(x,v,find(v),i+1>>1);
	}
	for(i=headlca[x];i;i=elca[i].next)
	{
		u=elca[i].u;
		v=elca[i].v;
		find(u);
		find(v);
		ans[elca[i].note]=max(l[u],l[v]);
	}
	visit[x]=vis[x]=1;
	l[x]=len;
	f[x]=p;
}

void Kruskal()
{
	int i,j,k;
	int fa,fb;
	for(i=1;i<=n;i++)f[i]=i;
	for(i=1;i<=m;i++)scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].len);
	sort(road+1,road+m+1);
	for(i=1;i<=m;i++)
	{
		fa=find(road[i].u);
		fb=find(road[i].v);
		if(fa!=fb)
		{
			f[fa]=fb;
			add(road[i].u,road[i].v,road[i].len);
			add(road[i].v,road[i].u,road[i].len);
		}
	}
}

int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k;
	int a,b,c;
	scanf("%d%d%d",&n,&m,&p);
	Kruskal();
	memset(ans,-1,sizeof(ans));
	for(i=1;i<=n;i++)f[i]=i;
	for(i=1;i<=p;i++)
	{
		scanf("%d%d",&a,&b);
		addq(a,b);
		addq(b,a);
	}
	for(i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			ygylca(i,0,0);
			memset(visit,0,sizeof(visit));
		}
	}
	for(i=1;i<=p;i++)printf("%d\n",ans[i]);
	return 0;
}

TLE做法(或可优化)

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 20000
#define M 40000
#define Q 20000
using namespace std;
struct KSD
{
    int u,v,len;
    bool operator < (const KSD &a)const
    {return len<a.len;}
}e[M];
struct Query
{
    int u,v,ans,note;
}query[Q],stk[2][Q];
int n,m,q,top[2];
int f[N];
int find(int x)
{
    if(x==f[x])return x;
    return f[x]=find(f[x]);
}
int main()
{
//  freopen("test.in","r",stdin);
    int i,j,k;
    int flag,len,now;
    int u,v;
    scanf("%d%d%d",&n,&m,&q);
    for(i=1;i<=n;i++)f[i]=i;
    for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].len);
    for(i=1;i<=q;i++)scanf("%d%d",&query[i].u,&query[i].v),query[i].note=i;
    for(i=1;i<=q;i++)stk[0][i]=query[i];
    top[0]=q;sort(e+1,e+m+1);
    for(now=0,flag=1;top[now]&&flag<=m;top[now]=0,now^=1)
    {
        for(len=e[flag].len;e[flag].len==len;flag++)
        {
            f[find(e[flag].v)]=find(e[flag].u);
        }
        for(i=1;i<=top[now];i++)
        {
            u=stk[now][i].u;
            v=stk[now][i].v;
            if(find(u)==find(v))query[stk[now][i].note].ans=len;
            else stk[now^1][++top[now^1]]=stk[now][i];
        }
    }
    for(i=1;i<=q;i++)printf("%d\n",query[i].ans);
    return 0;
}


你可能感兴趣的:(ygylca,BZOJ3732,货车运输)