[模板]树上倍增+最大生成树

洛谷P1967 货车运输

题目描述

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入输出格式

输入格式:

输入文件名为 truck.in。

输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道

路。 接下来 m 行每行 3 个整数 x、 y、 z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意: x 不等于 y,两座城市之间可能有多条道路 。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。

 

输出格式:

输出文件名为 truck.out。

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

车不能到达目的地,输出-1。

 

输入输出样例

输入样例#1: 复制
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出样例#1: 复制
3
-1
3

说明

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q< 1,000;

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q< 1,000;

对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000。

解析:第一次打这种利用树上倍增求其他变量的题目,感到了顺序的可怕。。。一直是10分,发现只要交换相邻两行的位置,便100了。。。

      为防考试时出错,特此一记。

    这道题目很裸的生成树+倍增,很适合当模板打。

   但注意:   1.这题和线段树也一样坑。。。得明确更新的顺序:先更新最小值,在更新节点。

        2.记得对每棵树进行dfs/bfs。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rint register int 

template<class T>
inline void rd( T &x){
	x=0;bool f=0;char ch=getchar();
    while(!isdigit(ch)) {	f=(ch==45);ch=getchar();}
    while( isdigit(ch)) {	x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?(~x+1):x;}

inline int read(){
	int x=0;bool f=0;char ch=getchar();
	while(!isdigit(ch)){	f=(ch==45);ch=getchar();}
	while( isdigit(ch)){	x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x=f?(~x+1):x;
}

#define man 100010

int m,n,q;

struct link{
	int x,y,z;
	link(){
		z=0;
	}
}a[man<<1];
int cmp(link x,link y){
	return x.z>y.z;
}

int fa[man];

inline int find(int x){
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}

struct edge{
	int next,to,dis;
}e[man<<1];
int head[man<<1],num=0;

inline void add(int from,int to,int dis){
	e[++num].next=head[from];
	e[num].to=to;
	e[num].dis=dis;
	head[from]=num;
}

int logn,dep[man];
int minn_dis[man][30],f[man][30];
bool vis[man];

void dfs(int s,int father,int depth,int dis){
	vis[s]=1;
	f[s][0]=father;minn_dis[s][0]=dis;dep[s]=depth;
	for(rint i=head[s];i;i=e[i].next){
		int to=e[i].to;
		if(to==father) continue;
		dfs(to,s,depth+1,e[i].dis);
	}
	return ;
}

/*上述的dfs也可用以下的bfs运行*/
inline void bfs(int s)
{   f[s][0]=-1;dep[s]=0;vis[s]=1;
    queue<int>q;q.push(s);
    do
    {   int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].next)
        {   int to=e[i].to;
            if(!vis[to])
            {   minn_dis[to][0]=e[i].dis;
                f[to][0]=u;
                dep[to]=dep[u]+1;
                q.push(to);
                vis[to]=1;
                }
            }
       }while(q.size());
    }

inline int LCA(int x,int y)
{   int ans=0x7fffffff;
    if(dep[x]>dep[y]) swap(x,y);
    for(int i=0;i<logn;i++)
        if(((dep[y]-dep[x])>>i)&1) ans=min(ans,minn_dis[y][i]),y=f[y][i];
    if(x==y) return ans;
    for(int i=logn;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {   ans=min(ans,min(minn_dis[x][i],minn_dis[y][i]));
            x=f[x][i];y=f[y][i];
            }
    ans=min(ans,min(minn_dis[x][0],minn_dis[y][0]));
    return ans;
    }

int main(){
	memset(minn_dis,0x7f,sizeof(minn_dis));
	n=read();m=read();
	for(rint i=1;i<=m;i++){
		a[i].x=read();a[i].y=read();a[i].z=max(a[i].z,read());
	}
	for(rint i=1;i<=n;i++) fa[i]=i;
	sort(a+1,a+1+m,cmp);
	int temp=0;
	for(rint i=1;i<=m;i++){
		int xx=find(a[i].x),yy=find(a[i].y);
		if(xx==yy) continue;
		fa[xx]=yy;
		add(a[i].x,a[i].y,a[i].z);
		add(a[i].y,a[i].x,a[i].z);
		temp++;
		if(temp==n-1) break; 
	}
	memset(vis,0,sizeof(vis));
	for(rint i=1;i<=n;i++)
		if(!vis[i]) dfs(i,-1,0,0);
	logn=(int)(log(n)/log(2.0))+1;
	for(rint j=0;j<=logn;j++)
		for(rint i=1;i<=n;i++)
			if(f[i][j]<0) f[i][j+1]=-1;
			else {
				f[i][j+1]=f[f[i][j]][j];
				minn_dis[i][j+1]=min(minn_dis[i][j],minn_dis[f[i][j]][j]);
			}
	q=read();
	for(rint i=1;i<=q;i++){
		int x=read(),y=read();
		if(find(x)!=find(y)) printf("-1
");
		else printf("%d
",LCA(x,y));
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/Slager-Z/p/7808881.html