zoukankan      html  css  js  c++  java
  • [bzoj2125]最短路——仙人掌,圆方树

    题目大意

    求仙人掌上最短路.

    思路

    将仙人掌上的所有环给建立方点,所有环上的点作为圆点连在方点上面.

    考虑一个以1为根的树型结构,我们将所有环上的点和方点的距离设为该点离环上深度最小的点的最小距离.

    这样利用树上倍增来求解两点之间距离后,我们发现跨过的环(方点)上的路程就是环上的点离环上深度最小的点的最小距离,于是我们只需要判断一下lca是否是方点即可。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.3.3
     * Problem : luogu5263
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("luogu5263.in","r",stdin);
    	freopen("luogu5263.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    const int maxn=10000+10;
    const int maxm=20000+10;
    int n,m,q;
    int beg[maxn],to[maxm<<1],las[maxm<<1],w[maxm<<1],cnte=1;
    int dfn[maxn],low[maxn],cnt_dfn,pre[maxn];
    int tot,anc[maxn<<1][21],dep[maxn<<1],Log[maxn<<1];
    ll val[maxn<<1][21],ss[maxn<<1],ssum[maxn<<1];
    vector<int>G[maxn<<1];
    
    void add(int u,int v,int ww){
    	las[++cnte]=beg[u],beg[u]=cnte,to[cnte]=v,w[cnte]=ww;
    	las[++cnte]=beg[v],beg[v]=cnte,to[cnte]=u,w[cnte]=ww;
    }
    
    void tarjan(int u,int fe){
    	dfn[u]=low[u]=++cnt_dfn;
    	for(int i=beg[u];i;i=las[i]){
    		if((i^1)==fe)continue;
    		int v=to[i];
    		if(!dfn[v]){
    			pre[v]=i;
    			tarjan(v,i);
    			low[u]=min(low[u],low[v]);
    			if(low[v]>dfn[u])G[u].pb(v),val[v][0]=w[i];
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    	for(int i=beg[u];i;i=las[i]){
    		if((i^1)==fe)continue;
    		int v=to[i];
    		if(pre[v]!=i && dfn[v]>dfn[u]){
    			ll sum=w[i],s=w[i];
    			for(int p=v;p!=u;p=to[pre[p]^1])
    				sum+=w[pre[p]];
    			++tot;
    			G[u].pb(tot);
    			for(int p=v;p!=u;p=to[pre[p]^1]){
    				G[tot].pb(p);
    				ssum[p]=sum,ss[p]=s;
    				val[p][0]=min(s,sum-s),s+=w[pre[p]];
    			}
    		}
    	}
    }
    
    void init(){
    	read(n),read(m),read(q);
    	int u,v,ww;
    	REP(i,1,m){
    		read(u),read(v),read(ww);
    		add(u,v,ww);
    	}
    	REP(i,2,n<<1)Log[i]=Log[i>>1]+1;
    }
    
    void dfs(int u,int fh){
    	anc[u][0]=fh,dep[u]=dep[fh]+1;
    	REP(i,0,G[u].size()-1){
    		int v=G[u][i];
    		dfs(v,u);
    	}
    }
    
    ll solve(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	ll ret=0;
    	for(int d=Log[dep[x]-dep[y]];dep[x]!=dep[y];--d){
    		if(dep[anc[x][d]]>=dep[y])ret+=val[x][d],x=anc[x][d];
    	}
    	if(x==y)return ret;
    	for(int d=Log[dep[x]];d>=0;--d)
    		if(anc[x][d]!=anc[y][d]){
    			ret+=val[x][d],x=anc[x][d];
    			ret+=val[y][d],y=anc[y][d];
    		}
    	if(anc[x][0]>n){
    		return ret+min(abs(ss[x]-ss[y]),ssum[x]-abs(ss[x]-ss[y]));
    	}
    	else{
    		return ret+val[x][0]+val[y][0];
    	}
    }
    
    void work(){
    	tot=n;
    	tarjan(1,0);
    	dfs(1,0);
    	REP(j,1,15)REP(i,1,tot)
    		if((1<<j)<=dep[i]-1){
    			anc[i][j]=anc[anc[i][j-1]][j-1];
    			val[i][j]=val[i][j-1]+val[anc[i][j-1]][j-1];
    		}
    	int u,v;
    	REP(i,1,q){
    		read(u),read(v);
    		printf("%lld
    ",solve(u,v));
    	}
    }
    
    int main(){
    	File();
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    测试心得---杂七杂八
    Redis 集群缓存测试要点--关于 线上 token 失效 BUG 的总结
    linux基础
    如何获取新系统的业务逻辑?
    python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon)
    python笔记8-多线程threading之封装式
    redis监控key失效
    使用PageHepler分页
    使用token和redis怎样判断账户是否失效和异地登录
    JSONObject
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10467319.html
Copyright © 2011-2022 走看看