• [UOJ 87] #87. mx的仙人掌


    #87. mx的仙人掌

    UOJ 87

    1

    题目大意

    给出一个 (n) 个点,(m) 条边的带边权的仙人掌,定义两点之间距离为最短路长度,(Q) 次询问,每次给出 (cnt) 个点,问它们之间最远点对的距离。

    数据范围

    边权不超过 (2^{31} - 1)

    (n, sum cnt le 300000)

    时空限制

    5s, 512MB

    分析

    此题如果不是仙人掌,那就是每次建出虚树来 DP

    仙人掌求最短路也就是建出圆方树后根据 (lca) 分类讨论,那么,我们就根据圆方树建一个虚树,如果当前节点是圆点那么就和树的情况 ,如果当前节点为方点那么它的儿子提出来,在环上用单调队列更新答案即可

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <vector>
    using namespace std;
    inline char nc() {
    	return getchar();
    	static char buf[100000], *l = buf, *r = buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void read(T & x) {
    	x = 0; int f = 1, ch = nc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=nc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=nc();}
    	x *= f;
    }
    typedef long long ll;
    const int maxn = 300000 + 5;
    const int maxm = maxn * 2;
    const int maxe = maxm * 2;
    const int maxnode = maxn * 2;
    const int maxlog = 20;
    const int sigma_cnt = 300000 + 5;
    int n, m, Q, cnt, p[sigma_cnt]; ll an;
    int sta[sigma_cnt], que[sigma_cnt << 1];
    ll f[maxnode];
    int head[maxnode], ecnt;
    int dfc, dfn[maxnode], low[maxn], anc[maxn]; ll dist[maxn];
    int dep[maxnode], parent[maxnode][maxlog]; ll dis[maxnode];
    int bcnt; ll sum[maxn];
    map<int, int> E[maxn];
    vector<int> adj[maxnode];
    struct edge {
    	int to, nex; ll cost;
    	edge(int to=0, int nex=0, ll cost=0) : to(to), nex(nex), cost(cost) {}
    } g[maxe];
    inline void addedge1(int u, int v, int w) {
    	if(E[u].count(v)) E[u][v] = min(E[u][v], w); else E[u][v] = w;
    	if(E[v].count(u)) E[v][u] = min(E[v][u], w); else E[v][u] = w;
    }
    inline void addedge2(int u, int v, ll w) {
    	g[ecnt] = edge(v, head[u], w), head[u] = ecnt++;
    	g[ecnt] = edge(u, head[v], w), head[v] = ecnt++;
    }
    inline void addedge3(int u, int v) {
    	adj[u].push_back(v);
    }
    void tarjan(int u) {
    	low[u] = dfn[u] = ++dfc;
    	for(map<int, int> :: iterator it = E[u].begin(); it != E[u].end(); ++it) {
    		int v = it->first;
    		if(!dfn[v]) {	
    			dist[v] = dist[u] + it->second;
    			anc[v] = u; tarjan(v);
    			low[u] = min(low[u], low[v]);
    			if(low[v] > dfn[u]) {
    				addedge2(u, v, it->second);
    			}
    		}
    		else if(anc[u] != v) {
    			low[u] = min(low[u], dfn[v]);
    		} 
    	}
    	for(map<int, int> :: iterator it = E[u].begin(); it != E[u].end(); ++it) {
    		int v = it->first;
    		if(anc[v] != u && dfn[v] >= dfn[u]) {
    			int now = ++bcnt; sum[now] = dist[v] - dist[u] + it->second;
    			for(int x = v; ; x = anc[x]) {
    				ll t = dist[x] - dist[u]; addedge2(now + n, x, min(t, sum[now] - t));
    				if(x == u) break;
    			}
    		}
    	}
    }
    void dfs(int u) {
    	dfn[u] = ++dfc;
    	for(int i = 1; i < maxlog; ++i) {
    		parent[u][i] = parent[ parent[u][i - 1] ][i - 1];
    	}
    	for(int i = head[u]; ~ i; i = g[i].nex) {
    		int v = g[i].to; if(v == parent[u][0]) continue;
    		dep[v] = dep[u] + 1, dis[v] = dis[u] + g[i].cost;
    		parent[v][0] = u; dfs(v);
    	}
    }
    void jump(int & u, int k) {
    	for(int i = maxlog - 1; ~ i; --i) {
    		if(k >= (1 << i)) {
    			k -= 1 << i;
    			u = parent[u][i];
    		}
    	}
    }
    int lca(int u, int v) {
    	if(dep[u] > dep[v]) swap(u, v);
    	jump(v, dep[v] - dep[u]);
    	if(u == v) return u;
    	for(int i = maxlog - 1; ~ i; --i) {
    		if(parent[u][i] != parent[v][i]) {
    			u = parent[u][i];
    			v = parent[v][i];
    		}
    	}
    	return parent[u][0];
    }
    void update(int u, int n) {
    	static ll f[sigma_cnt << 1], g[sigma_cnt << 1];
    	for(int i = 1; i <= n; ++i) {
    		f[i] = dist[ sta[i] ], f[n + i] = f[i] + sum[u - ::n];
    		g[i] = ::f[ sta[i] ], g[n + i] = g[i];
    	}
    	n <<= 1; int l = 0, r = -1;
    	for(int i = 1; i <= n; ++i) {
    		while(l <= r && (f[i] - f[ que[l] ]) * 2 > sum[u - ::n]) l++;
    		if(l <= r) an = max(an, g[ que[l] ] - f[ que[l] ] + g[i] + f[i]);
    		while(l <= r && g[ que[r] ] - f[ que[r] ] <=  g[i] - f[i]) r--;
    		que[++r] = i;
    	}
    }
    void dp(int u) {
    	f[u] = 0; int top = 0;
    	for(unsigned int i = 0; i < adj[u].size(); ++i) {
    		int v = adj[u][i]; dp(v);
    	}
    	for(unsigned int i = 0; i < adj[u].size(); ++i) {
    		int v = adj[u][i];
    		if(u <= n) an = max(an, f[u] + f[v] + dis[v] - dis[u]);
    		else {
    			int s = v; jump(s, dep[v] - dep[u] - 1);
    			f[s] = f[v] + dis[v] - dis[s]; sta[++top] = s;
    		}
    		f[u] = max(f[u], f[v] + dis[v] - dis[u]);
    
    	}
    	if(u > n) update(u, top);
    	adj[u].clear();
    }
    int cmp(const int & a, const int & b) {
    	return dfn[a] < dfn[b];
    }
    void solve() {
    	read(cnt);
    	for(int i = 1; i <= cnt; ++i) read(p[i]);
    	sort(p + 1, p + cnt + 1, cmp), cnt = unique(p + 1, p + cnt + 1) - p - 1;
    	int top = 0; sta[++top] = p[1];
    	for(int i = 2; i <= cnt; ++i) {
    		int w = lca(sta[top], p[i]);
    		while(top > 1 && dep[ sta[top - 1] ] > dep[w]) {
    			addedge3(sta[top - 1], sta[top]); top--;
    		}
    		if(dep[sta[top]] > dep[w]) addedge3(w, sta[top--]);
    		if(w != sta[top]) sta[++top] = w;
    		sta[++top] = p[i];
    	}
    	while(top > 1) {
    		addedge3(sta[top - 1], sta[top]); top--;
    	}
    	an = 0; dp(sta[top]); printf("%lld
    ", an);
    }
    int main() {
    	read(n), read(m);
    	for(int i = 1; i <= m; ++i) {
    		int u, v, w;
    		read(u), read(v), read(w);
    		addedge1(u, v, w);
    	}
    	memset(head, -1, sizeof(head)); tarjan(1);
    	for(int i = 1; i <= n; ++i) E[i].clear(); 
    	dfc = 0; dfs(1);
    	read(Q);
    	for(int i = 1; i <= Q; ++i) solve();
    	return 0;
    }
    
  • 相关阅读:
    代数基本定义
    离散数学CONDITIONAL STATEMENTS
    欧几里德算法及其实现
    欧几里得 算法复杂度
    养成习惯
    解决在myeclipse中启动服务器就进入调试模式的方法
    oracle中对索引的操作
    schema在oracle里是什么意思(转:http://shanbei.info/schemainoraclewhatismeantin.html)
    java 加载properties 文件
    java.io.IOException: mark() not supported
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/10241991.html
Copyright © 2020-2023  润新知