zoukankan      html  css  js  c++  java
  • BZOJ 2125: 最短路(仙人掌 圆方树)

    题面

    BZOJ
    给出一棵仙人掌(每条边最多属于一个环),多次询问求两点最短路。

    题解

    建圆方树,分(lca)是圆点还是方点讨论一下。具体见 神犇yyb的博客。但是题目并没有保证没有重边,而这个链接里的代码是默认没有重边(也就是没有长度为二的环)的,所以下面这组数据可以(hack)他。

    2 2 1
    1 2 100
    2 1 200
    1 2

    显然答案是(100),但是上面链接中的博客出(200)

    正确的写法是内似边双的写法。而且找返祖边必须开个(vector)存一下。

    CODE

    注意仙人掌的边数是(2n)级别的。具体来说(n-1le mle 2n-2)

    #include <bits/stdc++.h>
    using namespace std;
    inline void read(int &x) {
    	char ch; while(!isdigit(ch=getchar()));
    	for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0');
    }
    const int MAXN = 10005;
    const int MAXM = 20005;
    int n, m, q;
    bool flg[MAXN]; int cir[MAXM];
    struct RST { //圆方树
    	int fir[MAXM], to[MAXM<<1], nxt[MAXM<<1], wt[MAXM<<1], cnt;
    	inline void add(int u, int v, int w) {
    		to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; wt[cnt] = w;
    		to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt; wt[cnt] = w;
    	}
    	int dfn[MAXM], tmr, seq[MAXM], sz[MAXM], dep[MAXM], fa[MAXM], son[MAXM], top[MAXM], dis[MAXM];
    	void dfs1(int u, int ff) {
    		dep[u] = dep[fa[u]=ff] + (sz[u]=1);
    		for(int i = fir[u], v; i; i = nxt[i])
    			if((v=to[i]) != ff) {
    				dis[v] = dis[u] + wt[i];
    				dfs1(v, u); sz[u] += sz[v];
    				if(sz[v] > sz[son[u]]) son[u] = v;
    			}
    	}
    	void dfs2(int u, int tp) {
    		seq[dfn[u] = ++tmr] = u; top[u] = tp;
    		if(son[u]) dfs2(son[u], tp);
    		for(int i = fir[u], v; i; i = nxt[i])
    			if((v=to[i]) != fa[u] && v != son[u])
    				dfs2(v, v);
    	}
    	int lca(int u, int v) {
    		while(top[u] != top[v]) {
    			if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
    			else v = fa[top[v]];
    		}
    		return dep[u] < dep[v] ? u : v;
    	}
    	int jump(int u, int v) { //u点跳到v点的儿子处
    		int re;
    		while(top[u] != top[v])
    			re = top[u], u = fa[top[u]];
    		return u == v ? re : seq[dfn[v]+1];
    	}
    	int dist(int u, int v) {
    		int k = lca(u, v);
    		if(k <= n) return dis[u] + dis[v] - 2*dis[k];
    		int a = jump(u, k), b = jump(v, k);
    		int d1 = dis[a]-dis[k], d2 = dis[b]-dis[k];
    		if(!flg[a]) d1 = cir[k]-d1;
    		if(!flg[b]) d2 = cir[k]-d2;
    		return dis[u]-dis[a] + dis[v]-dis[b] + min(abs(d1-d2), cir[k]-abs(d1-d2));
    	}
    	void pre() {
    		dfs1(1, 0); dfs2(1, 1);
    	}
    }T;
    int fir[MAXN], to[MAXN<<2], wt[MAXN<<2], nxt[MAXN<<2], cnt = 1;
    inline void link(int u, int v, int w) {
    	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; wt[cnt] = w;
    	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt; wt[cnt] = w;
    }
    int dfn[MAXN], low[MAXN], dep[MAXN], dis[MAXN], fa[MAXN], tmr, tot;
    int seq[MAXN];
    vector<pair<int,int> >vec[MAXN];
    void Build(int tp, int bt, int L) {
    	int top = dep[bt]-dep[tp]+1, C = L, d = 0;
    	for(int i = bt; i != tp; i = fa[i]) seq[top--] = i, C += dis[i]-dis[fa[i]];
    	seq[1] = tp; top = dep[bt]-dep[tp]+1; cir[++tot] = C;
    	for(int i = 1; i <= top; ++i) {
    		int mind = min(d, C-d);
    		T.add(tot, seq[i], mind);
    		flg[seq[i]] = (mind == d); //flg=0表示mind经过了返祖边,flg=1表示mind没有经过返祖边
    		d += dis[seq[i+1]]-dis[seq[i]];
    	}
    }
    
    void Dfs(int u, int ff) {
    	dfn[u] = low[u] = ++tmr;
    	for(int i = fir[u], v; i; i = nxt[i])
    		if((i^1) != ff) {
    			if(!dfn[v=to[i]]) {
    				dep[v] = dep[fa[v]=u] + 1;
    				dis[v] = dis[u] + wt[i];
    				Dfs(v, i), low[u] = min(low[u], low[v]);
    			}
    			else {
    				low[u] = min(low[u], dfn[v]);
    				vec[v].push_back(pair<int,int>(u, wt[i])); //返祖边标记
    			}
    			if(dfn[u] < low[v]) T.add(u, v, wt[i]);
    		}
    	for(int i = vec[u].size()-1; i >= 0; --i)
    		Build(u, vec[u][i].first, vec[u][i].second);
    }
    
    int main () {
    	read(n), read(m), read(q);
    	for(int i = 1, u, v, w; i <= m; ++i)
    		read(u), read(v), read(w), link(u, v, w);
    	tot = n; Dfs(1, 0); T.pre();
    	int x, y;
    	while(q--) {
    		read(x), read(y);
    		printf("%d
    ", T.dist(x, y));
    	}
    }
    
  • 相关阅读:
    VS调试技巧
    Git 分支
    WPF:如何高速更新Model中的属性
    Redis-4.0.11集群配置
    大压力下Redis参数调整要点
    统计UPD丢包工具
    查看Redis集群所有节点内存工具
    Redis集群命令行部署工具
    查看Redis集群主从对应关系工具
    Redis集群master选举时长测试
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12157446.html
Copyright © 2011-2022 走看看