zoukankan      html  css  js  c++  java
  • CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)

    神仙题。

    先考虑平方级别的暴力怎么做。

    明显答案有单调性,先二分 (c)

    先最短路预处理 (dis_u) 表示 (u) 到离它最近的充电站的距离(一开始把 (1)(k) 全部丢到优先队列里就行了)。

    考虑当前站在 (u) 点上时,剩余的电量是 (x)。注意到由于起点是充电站,就一定有 (xle c-dis_u)(考虑最后一个走到的充电站沿最短路走到这)

    如果 (x<dis_u),因为终点是充电站,肯定不可能再到终点。

    否则就可以走到最近的充电站再回来,(x) 就可以变成 (c-dis_u)。前面也推过不可能变得更大。

    于是就可以直接 DFS 了。

    void dfs(int u,ll x){
        if(x<0) return;
        vis1[u]=true;    //走到过这个点
        if(x<dis[u]) return;
        vis2[u]=true;    //走到过这个点并且电量大于dis[u]
        for(int i=head[u];i;i=nxt[i]){
            int v=to[i];
            if(vis2[v]) return;
            dfs(v,c-dis[u]-w[i]);
        }
    }
    

    怎么搞快点?

    由于走到 (u) 时要 (xge dis_u) 才有用,所以考虑我们会走一条边 ((u,v,w)),当且仅当 (c-dis_u-wge dis_v),即 (dis_u+dis_v+wle c)

    那么问题变成求一条从 (a)(b) 的路径使得路径上每条边的 (dis_u+dis_v+w) 的最大值最小(明显是满足条件的最小的 (c))。

    还不会?

    右转 NOIP2013 货车运输。

    如果用最小生成树或者 Kruskal 重构树,时间复杂度大概是 (O((n+m)log n+mlog m+mlog n+qlog n))。(最短路+给边排序+求树+LCA)

    (顺便提个并查集的做法:询问离线下来,森林中每棵树的根记录这里面有哪些点。使用按秩合并,每个点至多被合并 (log) 次。)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=600060;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    struct node{
    	ll d;
    	int id;
    	bool operator<(const node &nd)const{return d>nd.d;}
    };
    struct edge{
    	int u,v;
    	ll w;
    	bool operator<(const edge &e)const{return w<e.w;}
    }e[maxn];
    int n,m,k,q,el,head[maxn],to[maxn],nxt[maxn],w[maxn],u_fa[maxn];
    int cnt,el2,head2[maxn],to2[maxn],nxt2[maxn],fa[maxn],sz[maxn],son[maxn],top[maxn],dep[maxn];
    ll wnd[maxn],dis[maxn];
    priority_queue<node> pq;
    inline void add(int u,int v,int w_){
    	to[++el]=v;nxt[el]=head[u];head[u]=el;w[el]=w_;
    }
    inline void add2(int u,int v){
    	to2[++el2]=v;nxt2[el2]=head2[u];head2[u]=el2;
    }
    int getfa(int x){
    	return x==u_fa[x]?x:u_fa[x]=getfa(u_fa[x]);
    }
    void dfs1(int u,int f){
    	sz[u]=1;
    	dep[u]=dep[fa[u]=f]+1;
    	for(int i=head2[u];i;i=nxt2[i]){
    		int v=to2[i];
    		if(v==f) continue;
    		dfs1(v,u);
    		sz[u]+=sz[v];
    		if(sz[v]>sz[son[u]]) son[u]=v; 
    	}
    }
    void dfs2(int u,int topf){
    	top[u]=topf;
    	if(son[u]) dfs2(son[u],topf);
    	for(int i=head2[u];i;i=nxt2[i]){
    		int v=to2[i];
    		if(v==fa[u] || v==son[u]) continue;
    		dfs2(v,v);
    	}
    }
    int lca(int u,int v){
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v;
    }
    int main(){
    	n=read();m=read();k=read();q=read();
    	FOR(i,1,m){
    		int u=read(),v=read(),w=read();
    		add(u,v,w);add(v,u,w);
    		e[i]=(edge){u,v,w};
    	}
    	MEM(dis,0x3f);
    	FOR(i,1,k) pq.push((node){dis[i]=0,i});
    	while(!pq.empty()){
    		ll d=pq.top().d;
    		int u=pq.top().id;
    		pq.pop();
    		if(d!=dis[u]) continue;
    		for(int i=head[u];i;i=nxt[i]){
    			int v=to[i];
    			if(dis[v]>d+w[i]) pq.push((node){dis[v]=d+w[i],v});
    		}
    	}
    	FOR(i,1,m) e[i].w+=dis[e[i].u]+dis[e[i].v];
    	sort(e+1,e+m+1);
    	FOR(i,1,2*n) u_fa[i]=i;
    	cnt=n;
    	FOR(i,1,m){
    		int u=e[i].u,v=e[i].v;
    		ll w=e[i].w;
    		u=getfa(u);v=getfa(v);
    		if(u==v) continue;
    		u_fa[u]=u_fa[v]=++cnt;
    		wnd[cnt]=w;
    		add2(cnt,u);add2(cnt,v);
    	}
    	dfs1(cnt,0);dfs2(cnt,cnt); 
    	while(q--){
    		int u=read(),v=read();
    		printf("%lld
    ",wnd[lca(u,v)]);
    	}
    }
    
  • 相关阅读:
    HDU 2842 (递推+矩阵快速幂)
    HDU 2838 (DP+树状数组维护带权排序)
    HDU 2836 (离散化DP+区间优化)
    HDU 2831 (贪心)
    HDU 2818 (矢量并查集)
    HDU 2822 (BFS+优先队列)
    HDU 3090 (贪心)
    HDU 3089 (快速约瑟夫环)
    XCOJ 1103 (LCA+树链最大子段和)
    HDU 3078 (LCA+树链第K大)
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11920509.html
Copyright © 2011-2022 走看看