zoukankan      html  css  js  c++  java
  • [NOIP2013]货车运输

    [NOIP2013]货车运输

    一.前言

    ​ 一开始还因为写了两个add调了半天,之后又被同机房dalao hack掉了,慢慢改完又丧心病狂地压行还把快读压出 UKE ,总而言之,蛮痛苦的做起来。放个链接

    做题复现

    二.初步思路

    ​ 啊这,这个怎么做,反手一个 floyd 魔改方程帅气出手,啊不行不行,就算要用最短路某d开头算法看起来,也要牛批一点好吧。然后魔改魔改,打出了一个?(也不知道写没写对hhh

    void di(int s){
    	bool c[10005];
    	priority_queue<pair<int,int> > q;
    	q.push(make_pair(0,s));
    	while(!q.empty()){
    		int u=q.top().second;
    		q.pop();
    		for(int i=head[u];i;i=ne[i]){
    			int v=to[i];
    			int p=dis[i];
    			if(f[s][u]!=0)p=min(p,f[s][u]);
    			if(p>f[s][v]){
    				f[s][v]=p;
    				if(!c[v]){
    					c[v]=1;
    					q.push(make_pair(f[s][v],v));
    				}
    			}
    		}
    	}
    }
    

    然后转念一想,哎嘿,堆,路径上的最小值,这是prim啊!所以最小(其实最大)生成树浮现在了我眼前?

    然后就想出了结论,答案肯定在最大生成树上。这样才保证两个点之间路径上的最小值最大。于是求一个最大生成树

    三.思路进一步

    ​ 既然是最大生成树,用什么prim,反手kruskal埋伏他一手。然后稍微想想,对于一个图,最大生成树只有一个,根的话无所谓,扭曲一下就好。那么就方便的以1做个根吧!于是在原图上先求出最大生成树,把原图舍弃建一个新图(就是这里两个add混乱了qwq)

    void ku(){
    	for(int i=1;i<=n;++i)f[i]=i;
    	for(int i=1;i<=m;++i){
    		int x=e[i].l,y=e[i].r,f1=gf(x),f2=gf(y);
    		if(f1!=f2){
    			f[f1]=f2;
    			add(x,y,e[i].dis);
    			add(y,x,e[i].dis);
    		}
    	}
    }
    

    四.思路更近一步

    ​ 对于最大生成树上的任意两点,我们要求出他们简单路径上的最小值的大小,既然已经用1为根,那么这两个点就不一定在一颗子树上。此时需要求出 LCA,然后分别在以 LCA 断开后的两条路径上找最小值。,我这里用的是倍增求LCA

    ​ 对于倍增法来说,有 (f[x][i]) 表示 x 的第 (2^i)个父亲,那么顺着这个思路魔改一下,则有 (minn[x][i]) 表示从 x 到 x的第(2^i) 个父亲的路径上的最小值,这两个转移方程差不多其实。

    ​ 那么在LCA的时候就求得出路径上最小值的大小啦!

    五.奇奇怪怪的HACK

    ​ 此时有一个很神奇的东西,就是这不一定是一个连通图,题目并没有说。那么虽然数据很水可以采用奇怪的方法,但是我们还是要考虑周全。

    ​ 一般的求生成树都会有一个限制选 n-1 条边的条件以判断是否可以生成,但是很显然,我上面的代码里面没有这个东西,因为我其实求的是最大生成森林。根据并查集的性质,如果不限制边的话,就算原图不连通,也会形成一个最大生成森林,且每个生成树都在一个集合内,即他们有着同一个祖先

    ​ 那么再来看最后询问的时候,如果两个点不在同一个集合中,那么肯定走不到,输出-1就行,那么如果在一个集合中就看这个集合代表的树有没有预处理过,只有预处理过后才能LCA,如果没有,就以代表集合的那个祖先为根预处理就行。如果有,LCA输出答案。

    六.CODE

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAXN=50005;
    int n,m,q;
    int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+(ch-'0');
    	return res*f;
    }
    struct p{
    	int l,r,dis;
    }e[MAXN];
    void adde(int x,int y,int d,int i){e[i].l=x;e[i].r=y;e[i].dis=d;}
    bool cmp(p a,p b){return a.dis>b.dis;}
    int f[10005];
    int gf(int x){
    	if(f[x]==x)return x;
    	return f[x]=gf(f[x]);
    }
    int head[MAXN],ne[2*MAXN],to[2*MAXN],dis[2*MAXN],tot;
    void add(int x,int y,int d){dis[++tot]=d,to[tot]=y,ne[tot]=head[x],head[x]=tot;}
    void ku(){
    	for(int i=1;i<=n;++i)f[i]=i;
    	for(int i=1;i<=m;++i){
    		int x=e[i].l,y=e[i].r,f1=gf(x),f2=gf(y);
    		if(f1!=f2){
    			f[f1]=f2;
    			add(x,y,e[i].dis);
    			add(y,x,e[i].dis);
    		}
    	}
    }
    int fa[10005][25],dep[10005],minn[10005][25];
    void dfs1(int x,int pre){
    	dep[x]=dep[pre]+1;
    	for(int i=0;i<=18;i++)
    		fa[x][i+1]=fa[fa[x][i]][i],minn[x][i+1]=min(minn[x][i],minn[fa[x][i]][i]);
    	for(int i=head[x];i;i=ne[i]){
    		if(to[i]==pre)continue;
    		fa[to[i]][0]=x,minn[to[i]][0]=dis[i];
    		dfs1(to[i],x);
    	}
    }
    int LCA(int x,int y){
    	int ans=1<<30;
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;--i)
    		if(dep[fa[x][i]]>=dep[y])ans=min(ans,minn[x][i]),x=fa[x][i];
    	if(x==y)return ans;
    	for(int i=19;i>=0;--i)
    		if(fa[x][i]!=fa[y][i])
    		ans=min(ans,min(minn[x][i],minn[y][i])),x=fa[x][i],y=fa[y][i];
    	return min(ans,min(minn[x][0],minn[y][0]));
    }
    bool vis[10005];
    int main(){
    	n=read();m=read();
    	for(int i=1,l,r,k;i<=m;++i){
    		l=read();r=read();k=read();
    		adde(l,r,k,i);
    	}
    	sort(e+1,e+m+1,cmp);
    	ku();
    	q=read();
    	for(int i=1,s,t;i<=q;++i){
    		s=read();t=read();
    		int f1=gf(s),f2=gf(t);
    		if(f1!=f2)cout<<"-1"<<endl;
    		else{
    			if(!vis[f1]){vis[f1]=1;dfs1(f1,0);}
    			cout<<LCA(s,t)<<endl;
    		}
    	}
    	return 0;
    }
    

    七.时间复杂度

    ​ 虽然感觉上预处理了很多次,但是每个点只访问了一次,是(O(n)),然后有一个sort (O(mlogm)),LCA用了q次是(O(qlogn))所以总的不算慢。

  • 相关阅读:
    Mac的Safari安装油猴插件(Tampermonkey)
    element表格点击行即选中该行复选框
    Previous operation has not finished; run 'cleanup' if it was interrupted最简单有效的解决方法
    读取JDK API文档,并根据单词出现频率排序
    Mac 下安装并配置 Tomcat
    Mac上安装并配置JDK
    GitHub注册失败,卡在第一步
    Jmeter 操作手册(三)
    Jmeter 操作手册(二)
    .Jmeter 使用手册(一)
  • 原文地址:https://www.cnblogs.com/clockwhite/p/13370493.html
Copyright © 2011-2022 走看看