zoukankan      html  css  js  c++  java
  • Codeforces 786B Legacy(线段树优化建图)

    题目链接  Legacy

    首先对于输入的$n$,建立一棵线段树。

    显然线段树有大概$2n$个结点,每个节点对应一段区间

    我们把这$2n$个结点加入我们的无向图中,一起跑最短路。

    具体连边方案:

    我们把这棵线段树复制一下,另外一棵倒过来。

    首先第一棵线段树,每个结点向他的两个儿子连有向边,连到叶子结点的时候

    叶子结点向原来的$n$个点连边

    也就是说$[l, l]$向原来编号为$l$的这个点连边。

    然后$1$到$n$这$n$个点分别向第二棵线段树的叶子结点分别连有向边

    具体一点,$l$号点向$[l', l']$连边。

    然后在第二棵线段树中,两个儿子向父亲连边,依次类推。

    接着就是对给定的输入进行连边操作了。

    对于点连向点的,普通操作就行了。

    对于点连向区间的,把点连向第一棵线段树的结点。大概要连$logn$条边

    对于区间连向点的,把第二棵线段树的结点连向这个点。大概也连$logn$条边

    然后跑一边堆优化Dij就可以了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define	ls		(i << 1)
    #define	rs		(i << 1 | 1)
    #define	mid		((L + R) >> 1)
    #define	lson		ls, L, mid
    #define	rson		rs, mid + 1, R
    
    
    typedef long long LL;
    typedef pair <int, int> PII;
    
    const int N = 2e6 + 10;
    
    struct node{
    	int u;
    	LL w;
    	friend bool operator < (const node &a, const node &b){
    		return a.w > b.w;
    	}
    };
    
    map <PII, int> mp;
    int tot = 0;
    int n, q, s, cnt;
    LL dis[N];
    vector <node> v[N];
    
    void addedge(int x, int y, LL z){
    	v[x].push_back({y, z});
    }
    
    void build(int i, int L, int R){
    	cnt = max(cnt, i);
    	if (L == R){
    		addedge(i + n, L, 0);
    		return;
    	}
    
    	build(lson);
    	build(rson);
    	addedge(i + n, ls + n, 0);
    	addedge(i + n, rs + n, 0);	
    }
    
    void build2(int i, int L, int R){
    	if (L == R){
    		addedge(L, i + n + cnt, 0);
    		return;
    	}
    
    	build2(lson);
    	build2(rson);
    	addedge(ls + n + cnt, i + n + cnt, 0);
    	addedge(rs + n + cnt, i + n + cnt, 0);
    }
    
    
    void work1(int i, int L, int R, int l, int r, int u, LL val){
    	if (l <= L && R <= r){
    		addedge(u, i + n, val);
    		return;
    	}
    
    	if (l <= mid) work1(lson, l, r, u, val);
    	if (r >  mid) work1(rson, l, r, u, val);
    }
    
    void work2(int i, int L, int R, int l, int r, int u, LL val){
    	if (l <= L && R <= r){
    		addedge(i + n + cnt, u, val);
    		return;
    	}
    
    	if (l <= mid) work2(lson, l, r, u, val);
    	if (r >  mid) work2(rson, l, r, u, val);
    }
    
    void dij(int s, LL dis[], vector <node> v[]){
    	priority_queue <node> q;
    	static bool vis[N];
    	rep(i, 1, 2e6) dis[i] = 1e18, vis[i] = false;
    	q.push({s, 0});
    	dis[s] = 0;
    	while (!q.empty()){
    		int u = q.top().u; q.pop();
    		if (vis[u]) continue;
    		vis[u] = 1;
    		for (auto edge : v[u]) if (dis[u] + edge.w < dis[edge.u]){
    			dis[edge.u] = dis[u] + edge.w;
    			q.push({edge.u, dis[edge.u]});
    		}
    	}
    }
    
    int main(){
    
    	scanf("%d%d%d", &n, &q, &s);
    	tot = n;
    	build(1, 1, n);
    	build2(1, 1, n);
    
    	while (q--){
    		int op;
    		scanf("%d", &op);
    		if (op == 1){
    			int x, y;
    			LL z;
    			scanf("%d%d%lld", &x, &y, &z);
    			if (x == y) continue;
    			addedge(x, y, z);
    		}
    		else if (op == 2){
    			int u, l, r;
    			LL z;
    			scanf("%d%d%d%lld", &u, &l, &r, &z);
    			work1(1, 1, n, l, r, u, z);
    		}
    
    		else{
    			int u, l, r;
    			LL z;
    			scanf("%d%d%d%lld", &u, &l, &r, &z);
    			work2(1, 1, n, l, r, u, z);
    		}
    	}
    
    	dij(s, dis, v);
    	rep(i, 1, n) printf("%lld
    ", (dis[i] < 1e18 ? dis[i] : -1));
    	return 0;
    }
    
  • 相关阅读:
    二分图 洛谷P2055 [ZJOI2009]假期的宿舍
    并查集 洛谷P1640 [SCOI2010]连续攻击游戏
    贪心 洛谷P2870 Best Cow Line, Gold
    贪心 NOIP2013 积木大赛
    快速幂 NOIP2013 转圈游戏
    倍增LCA NOIP2013 货车运输
    树形DP 洛谷P2014 选课
    KMP UVA1328 Period
    动态规划入门 BZOJ 1270 雷涛的小猫
    KMP POJ 2752Seek the Name, Seek the Fame
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7953759.html
Copyright © 2011-2022 走看看