【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;
}

复制去Google翻译翻译结果

时间: 2024-10-24 12:50:54

【BZOJ3732】Network,NOIP2013货车运输,ygylca的相关文章

poj1330|bzoj3732|noip2013 货车运输 kruskal+倍增lca

学了一早上倍增,感觉lca还是tarjan好写. poj1330 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #include <algorithm> 5 #define DEG 20//2^20 6 #define maxn 10010 7 using namespace std; 8 struct node 9 { 10 int v, next; 11 }a[maxn*2

倍增LCA NOIP2013 货车运输

货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条

noip2013货车运输

P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y

Codevs3278[NOIP2013]货车运输

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和

【NOIP2013货车运输】

描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 格式 输入格式 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路. 接下来 m 行每行 3 个整数 x.y.z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路.注意:x 不等于 y,两座城市之间可能有多条道路. 接

NOIP2013 货车运输(最大生成树+LCA)

模拟考试的时候暴搜,结果写丑了,分都不分 下来啃了一下题解,发现要用到一个叫做倍增的东西,还没有学过.但是老师说的,没有那个东西,写暴力也有30~40分... 我觉得最大生成树还是很好理解的,因为我们要求的是图中任意两个点之间的路径上,使得边权的最小值尽量大.因此首先求最大生成树. 当我们得到最大生成树后,要求两个点之间边权最小值,我们可以首先找到他们的公共祖先.这里有一篇写得很详细的代码,并且注明了各种写法的得分http://blog.csdn.net/gengmingrui/article/

[NOIP2013]货车运输

[题目描述] 思路{直接最大生成树+树链剖分即可.} 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #include<vector> 8 #include<set> 9 #include<map> 10 #d

洛谷 1967 NOIP2013 货车运输

这个题目在看题解的情况下,写了6小时左右.感觉贼心累啊.读入错误,运行顺序错误,一大堆错误.现在很为自己写长代码担心... 毕竟花了这么长时间,在考场那种高压的情况下.还不知道发挥如何~ 题目说起来很Easy:1.读入2.求最大生成树3.求倍增求LCA 并记录 路径上的 最小值4.输出 放出我的丑不拉几的代码~ 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4   5 int Min[20

洛谷P1967 [NOIP2013提高组Day1T2]货车运输

P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y