• 【SDOI2017】天才黑客


    题面

    题解

    这是好久之前菊开讲的一道题目了。

    可以发现在这道题目中,边比点更加重要,所以我们化边为点,将边权改为点权,边与边之间的边权就是题目所给的Trie树上LCA深度的和。

    想到一个平方的暴力,每条边和它连向的点的出边连一条边。下一步考虑怎么优化。

    对于每一个点,将它的入边和出边都拿出来,按照dfs序排序,那么可以考虑将每个点拆成入点和出点,因为(operatorname{lcp}(i, j))的值是(i o j)之间所有的边的(operatorname{lcp})的最小值,于是前后缀优化连边就可以了。

    可以考虑使用下面这个图来帮助理解:

    graph.png

    说起来容易做起来难,代码留给读者作为练习

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if (ch == '-') w = -1, ch = getchar();
    	while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int N(50010);
    struct edge { int to, dis; };
    int T, n, m, K, val[N * 20], pos[N], dis[N * 20], vis[N * 20], cur;
    std::vector<int> in[N], out[N];
    std::vector<edge> G[N * 20];
    namespace Tree
    {
    	int fa[N], size[N], heavy[N], dfn[N], bel[N], dep[N], cnt; std::vector<int> T[N];
    	inline void Add(int x, int y) { T[x].push_back(y); }
    	void dfs(int x)
    	{
    		size[x] = 1, heavy[x] = 0;
    		for (auto i : T[x])
    		{
    			fa[i] = x, dep[i] = dep[x] + 1, dfs(i), size[x] += size[i];
    			if (size[heavy[x]] < size[i]) heavy[x] = i;
    		}
    	}
    
    	void dfs(int x, int chain)
    	{
    		dfn[x] = ++cnt, bel[x] = chain;
    		if (heavy[x]) dfs(heavy[x], chain);
    		for (auto i : T[x]) if (i != heavy[x]) dfs(i, i);
    	}
    
    	int LCA(int x, int y)
    	{
    		for (; bel[x] != bel[y]; x = fa[bel[x]])
    			if (dfn[bel[x]] < dfn[bel[y]]) std::swap(x, y);
    		return dfn[x] < dfn[y] ? dep[x] : dep[y];
    	}
    }
    
    void Dijkstra()
    {
    	std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >,
    		std::greater<std::pair<int, int> > > Q;
    	memset(dis, 127, (cur + 1) << 2), memset(vis, 0, sizeof vis);
    	for (auto i : out[1]) Q.push(std::make_pair(dis[i] = val[i], i));
    	while (!Q.empty())
    	{
    		int x = Q.top().second; Q.pop(); if (vis[x]) continue; vis[x] = 1;
    		for (auto i : G[x]) if (dis[x] + val[i.to] + i.dis < dis[i.to])
    			Q.push(std::make_pair(dis[i.to] = dis[x] + val[i.to] + i.dis, i.to));
    	}
    }
    
    int Abs(int x) { return x < 0 ? -x : x; }
    int cmp(int x, int y) { return Tree::dfn[pos[Abs(x)]] < Tree::dfn[pos[Abs(y)]]; }
    void Link(int x)
    {
    	static int stk[N], p1[N], p2[N], q1[N], q2[N]; int top = 0;
    	for (auto i : in[x]) stk[++top] = i;
    	for (auto i : out[x]) stk[++top] = -i;
    	std::sort(stk + 1, stk + top + 1, cmp);
    	for (int i = 1; i <= top; i++)
    		p1[i] = ++cur, p2[i] = ++cur, q1[i] = ++cur, q2[i] = ++cur;
    	for (int i = 2; i <= top; i++)
    		G[p1[i - 1]].push_back((edge) {p1[i], 0}),
    		G[q1[i - 1]].push_back((edge) {q1[i], 0}),
    		G[p2[i]].push_back((edge) {p2[i - 1], 0}),
    		G[q2[i]].push_back((edge) {q2[i - 1], 0});
    	for (int i = 1; i <= top; i++)
    		if (stk[i] > 0) G[stk[i]].push_back((edge) {p1[i], 0}),
    						G[stk[i]].push_back((edge) {p2[i], 0});
    		else stk[i] = -stk[i], G[q1[i]].push_back((edge) {stk[i], 0}),
    							   G[q2[i]].push_back((edge) {stk[i], 0});
    	for (int i = 1, x; i < top; i++)
    		x = Tree::LCA(pos[stk[i]], pos[stk[i + 1]]),
    		G[p1[i]].push_back((edge) {q1[i + 1], x}),
    		G[p2[i + 1]].push_back((edge) {q2[i], x});
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	file(cpp);
    #endif
    	for (T = read(); T--; )
    	{
    		n = read(), m = cur = read(), K = read();
    		memset(val, 0, sizeof val), Tree::cnt = 0;
    		for (int i = 1, x, y; i <= m; i++)
    			x = read(), y = read(), val[i] = read(), pos[i] = read(),
    			out[x].push_back(i), in[y].push_back(i);
    		for (int i = 1, x, y; i < K; i++)
    			x = read(), y = read(), read(), Tree::Add(x, y);
    		Tree::dfs(1), Tree::dfs(1, 1);
    		for (int i = 2; i <= n; i++) Link(i);
    		Dijkstra();
    		for (int i = 2; i <= n; i++)
    		{
    			int ans = 2e9;
    			for (auto x : in[i]) ans = std::min(ans, dis[x]);
    			printf("%d
    ", ans);
    		}
    		for (int i = 1; i <= cur; i++) G[i].clear();
    		for (int i = 1; i <= n; i++) in[i].clear(), out[i].clear();
    		for (int i = 1; i <= K; i++) Tree::T[i].clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    单表清除重复数据
    调用webApi封装
    简单写入本地日志,日志文件位置与主程序exe位置相同
    APPConfig.XML获取配置文件(主程序和Dll各自的)
    获取当前运行程序上一级目录指定文件夹,没有就创建文件夹
    shell脚本中的单引号和双引号以及反引号详解
    Linux shell中反引号(`)的应用
    关于网页 硬解 软解 H264 HEVC 和你电脑起飞了那点事
    浏览器支持H.265解码总结
    微软、谷歌、亚马逊、Facebook等硅谷大厂91个开源软件盘点(附下载地址)
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/11688112.html
Copyright © 2020-2023  润新知