• CF786B Legacy(线段树优化建图)


    嘟嘟嘟


    省选Day1T2不仅考了字符串,还考了线段树优化建图。当时不会,现在赶快学一下。


    线段树能优化的图就是像这道题一样,一个点像一个区间的点连边,或一个区间像一个点连边。一个个连就是(O(n ^ 2))复杂度了,当然承受不起。于是就有了线段树了。
    原理很简单,就是把一个连续区间的点合并成线段树上的一个点,这样最多有(nlogn)个点。但仅仅这样还不对,所以我们要建两棵树,一个是入度树,一个是出度树。
    对于入度树,每一个点要像左右儿子连边,因为如果这个有人像这个点所代表的区间连边,那么也一定能进入他的左右子区间。
    对于出度树,左右儿子向父亲连边,因为如果这个点所代表的区间能走到一个点,则他的父亲也一定能到那个点。
    而这种连边反过来就不行。
    这样我们线段树内部的连边就搞完了,接下来考虑题中的加边。


    对于一个点(v)向一个区间连边,就在入度树上区间修改,如果到了递归边界,就从(v)向这个点的编号连边;对于区间向点连边同理,这里就不说了。


    上面提到点的编号,有一个很好的方法就是线段树的节点从(n + 1)开始编号,这样原图上的点的编号不会被打乱,点对点的加边还可以正常加。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const ll INF = 1e18;
    const db eps = 1e-8;
    const int maxn = 5e6 + 5;
    const int maxe = 1e7 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, m, s;
    struct Edge
    {
    	int nxt, to, w;
    }e[maxe];
    int head[maxn], ecnt = -1;
    In void addEdge(int x, int y, int w)
    {
    	e[++ecnt] = (Edge){head[x], y, w};
    	head[x] = ecnt;
    }
    
    int tIn[maxn], tOut[maxn], l[maxn], r[maxn], tcnt = 0;
    In void build(int now, int L, int R)
    {
    	l[now] = L; r[now] = R;
    	if(L == R)
    	{
    		tIn[now] = tOut[now] = L;
    		return;
    	}
    	tIn[now] = ++tcnt; tOut[now] = ++tcnt;
    	int mid = (L + R) >> 1;
    	build(now << 1, L, mid);
    	build(now << 1 | 1, mid + 1, R);
    	addEdge(tIn[now], tIn[now << 1], 0);
    	addEdge(tIn[now], tIn[now << 1 | 1], 0);
    	addEdge(tOut[now << 1], tOut[now], 0);
    	addEdge(tOut[now << 1 | 1], tOut[now], 0);
    }
    In void update(int now, int L, int R, int x, int w, bool flg)
    {
    	if(l[now] == L && r[now] == R)
    	{
    		if(flg) addEdge(x, tIn[now], w);
    		else addEdge(tOut[now], x, w);
    		return;
    	}
    	int mid = (l[now] + r[now]) >> 1;
    	if(R <= mid) update(now << 1, L, R, x, w, flg);
    	else if(L > mid) update(now << 1 | 1, L, R, x, w, flg);
    	else update(now << 1, L, mid, x, w, flg), update(now << 1 | 1, mid + 1, R, x, w, flg);
    }
    
    #define pr pair<ll, int>
    #define mp make_pair
    bool in[maxn];
    ll dis[maxn];
    In void dijkstra(int s)
    {
    	fill(dis + 1, dis + tcnt + 1, INF); dis[s] = 0;
    	priority_queue<pr, vector<pr>, greater<pr> > q;
    	q.push(mp(dis[s], s));
    	while(!q.empty())
    	{
    		int now = q.top().second; q.pop();
    		if(in[now]) continue;
    		in[now] = 1;
    		for(int i = head[now], v; ~i; i = e[i].nxt)
    		{
    			if(dis[v = e[i].to] > dis[now] + e[i].w)
    			{
    				dis[v] = dis[now] + e[i].w;
    				q.push(mp(dis[v], v));
    			}
    		}
    	}
    }
    
    int main()
    {
    	Mem(head, -1);
    	n = read(), m = read(), s = read();
    	tcnt = n; build(1, 1, n);
    	for(int i = 1; i <= m; ++i)
    	{
    		int op = read(), x = read();
    		if(op == 1)
    		{
    			int y = read(), w = read();
    			addEdge(x, y, w);
    		}
    		else
    		{
    			int L = read(), R = read(), w = read();
    			update(1, L, R, x, w, op == 2);
    		}
    	}
    	dijkstra(s);
    	for(int i = 1; i <= n; ++i) write(dis[i] == INF ? -1 : dis[i]), space; enter;
    	return 0;
    }
    
  • 相关阅读:
    PHP开发者常犯的MySQL错误
    linux 用户管理
    php中mysql数据库异步查询实现
    PHP 安全相关 简单知识
    js倒计时 网上流传最多的
    TP学习笔记
    Java Map
    Java集合技巧
    Java集合之HashSet/TreeSet原理
    Java Set
  • 原文地址:https://www.cnblogs.com/mrclr/p/10778733.html
Copyright © 2020-2023  润新知