zoukankan      html  css  js  c++  java
  • 原题的旅行

    ### Description

      数据范围:(n<=10^5,m<=2*10^5,q<=10^5,1<=w_i<=10^9)

      

    Solution

      有一个比较简单粗暴的想法是先将文明城市之间的两两最短路预处理出来,然后建MST,对于一个询问直接在树上倍增就好了

      但是现在的问题是这样的话边数是(n^2)的,所以我们考虑另一种建图方式

      我们考虑对于每一个点(x)预处理出到它最近的文明城市是那个,以及它们之间的最短距离,分别记为(from[x])(dis[x]),然后对于原图中的一条边((x,y,w)),如果说(from[x] eq from[y]),我们就往新图里面加一条((from[x],from[y],dis[x]+w+dis[y]))的边,这样总的边数是(m)的,然后在新图里面MST再倍增什么的就好了

      
    ​  这样是对的是因为:首先这样的一条边一定有机会成为MST中的一条边,然后现在我们只要考虑有没有遗漏的情况,假设(a)(b)是两个文明城市,这两个城市之间的最短路是MST中的一条边,但是并没有被上面的那种方式枚举到

      然后(a)(b)(a eq b))间的最短路一定是由原图的边组成的,因为题目保证(w_i)(边权)(>=1)(a eq b),所以最短路中必定存在至少一条边((u,v))满足(from[u] eq from[v]),假设所有满足两个端点的(from)值不等的边中没有一条两端的(from)同时是(a)(b),那么就说明这条路径上面至少有一个点到(a)或者到(b)的路径不是最短的,然后因为最短路径的传递性,这一条路自然也就不是最短路了,与我们前面的假设矛盾,所以一定不存在这样的遗漏情况

      

      mark:预处理(dis)(from)可以直接用(dij)做到(O(nlogn)),一开始的时候把所有的文明城市丢进堆里面就好了

      

      代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=1e5+10,M=2e5+10;
    const ll inf=1LL<<60;
    int mark[N];
    int n,m,Q,cntgood;
    namespace T{/*{{{*/
    	const int TOP=20;//just for debuging
    	struct xxx{
    		int y,nxt;
    		ll dis;
    	}a[N*2];
    	int h[N],f[N][TOP+1],dep[N];
    	ll mx[N][TOP+1];
    	int tot,n;
    	void init(int _n){memset(h,-1,sizeof(h)); tot=0; n=_n;}
    	void add(int x,int y,ll d){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].dis=d;}
    	void dfs(int fa,int x,int d){
    		int u;
    		dep[x]=d; f[x][0]=fa;
    		for (int i=1;i<=TOP;++i){
    			f[x][i]=f[f[x][i-1]][i-1];
    			mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]);
    		}
    		for (int i=h[x];i!=-1;i=a[i].nxt){
    			u=a[i].y;
    			if (u==fa) continue;
    			mx[u][0]=a[i].dis;
    			dfs(x,u,d+1);
    		}
    	}
    	ll query(int x,int y){
    		ll ret=0;
    		if (dep[x]<dep[y]) swap(x,y);
    		for (int i=TOP;i>=0;--i)
    			if (dep[f[x][i]]>=dep[y]){
    				ret=max(ret,mx[x][i]);
    				x=f[x][i];
    			}
    		if (x==y) return ret;
    		for (int i=TOP;i>=0;--i)
    			if (f[x][i]!=f[y][i]){
    				ret=max(ret,mx[x][i]);
    				ret=max(ret,mx[y][i]);
    				x=f[x][i],y=f[y][i];
    			}
    		return max(ret,max(mx[x][0],mx[y][0]));
    	}
    }/*}}}*/
    namespace G{/*{{{*/
    	struct xxx{
    		int y,nxt,dis;
    	}a[M*2];
    	struct Edge{
    		int x,y;
    		ll dis;
    		Edge(){}
    		Edge(int x1,int y1,ll dis1){x=x1; y=y1; dis=dis1;}
    		friend bool operator < (Edge x,Edge y){return x.dis<y.dis;}
    	}rec[M];
    	struct Data{
    		int node,dis;
    		Data(){}
    		Data(int node1,int dis1){node=node1; dis=dis1;}
    		friend bool operator < (Data x,Data y){return x.dis>y.dis;}
    	};
    	priority_queue<Data> q;
    	int h[N],f[N],vis[N];
    	ll dis[N],from[N];
    	int tot,totrec;
    	void init(){memset(h,-1,sizeof(h)); tot=-1;}
    	void add(int x,int y,int d){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].dis=d;}
    	void dij(){
    		int u,v;
    		while (!q.empty()) q.pop();
    		for (int i=1;i<=n;++i) dis[i]=inf,vis[i]=0;
    		for (int i=1;i<=n;++i)
    			if (mark[i])
    				from[i]=i,dis[i]=0,q.push(Data(i,dis[i]));
    		while (!q.empty()){
    			v=q.top().node; q.pop();
    			if (vis[v]) continue;
    			vis[v]=1;
    			for (int i=h[v];i!=-1;i=a[i].nxt){
    				u=a[i].y;
    				if (vis[u]) continue;
    				if (dis[u]>dis[v]+a[i].dis){
    					dis[u]=dis[v]+a[i].dis;
    					from[u]=from[v];
    					q.push(Data(u,dis[u]));
    				}
    			}
    		}
    	}
    	int get_f(int x){return f[x]=f[x]==x?x:get_f(f[x]);}
    	void build(){
    		dij();
    		int x,y;
    		ll w;
    		for (int i=0;i<=tot;i+=2){
    			x=a[i^1].y; y=a[i].y; w=a[i].dis;
    			if (from[x]!=from[y])
    				rec[++totrec]=Edge(from[x],from[y],w+dis[x]+dis[y]);
    		}
    		for (int i=1;i<=n;++i) f[i]=i;
    		sort(rec+1,rec+1+totrec);
    		int cnt=0;
    		T::init(cntgood);
    		for (int i=1;i<=totrec&&cnt<cntgood-1;++i){
    			x=rec[i].x; y=rec[i].y; w=rec[i].dis;
    			if (get_f(x)==get_f(y)) continue;
    			f[f[x]]=f[y];
    			T::add(x,y,rec[i].dis);
    			T::add(y,x,rec[i].dis);
    			++cnt;
    		}
    	}
    }/*}}}*/
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int x,y,z;
    	char ch;
    	scanf("%d%d
    ",&n,&m);
    	cntgood=0;
    	for (int i=1;i<=n;++i)
    		scanf("%c",&ch),mark[i]=ch=='1',cntgood+=mark[i];
    	G::init();
    	for (int i=1;i<=m;++i){
    		scanf("%d%d%d",&x,&y,&z);
    		G::add(x,y,z);
    		G::add(y,x,z);
    	}
    	G::build();
    	for (int i=1;i<=n;++i)
    		if (mark[i]){
    			T::dfs(0,i,1);
    			break;
    		}
    	scanf("%d",&Q);
    	for (int i=1;i<=Q;++i){
    		scanf("%d%d",&x,&y);
    		printf("%lld
    ",T::query(x,y));
    	}
    }
    
  • 相关阅读:
    SGU 495 Kids and Prizes 概率DP 或 数学推理
    poj 2799 IP Networks 模拟 位运算
    uva 202 Repeating Decimals 模拟
    poj 3158 Kickdown 字符串匹配?
    uva 1595 Symmetry 暴力
    uva 201 Squares 暴力
    uva 1594 Ducci Sequence 哈希
    uva 1368 DNA Consensus String 字符串
    数字、字符串、列表的常用操作
    if条件判断 流程控制
  • 原文地址:https://www.cnblogs.com/yoyoball/p/10022742.html
Copyright © 2011-2022 走看看