• 线段树优化连边


    有的时候,

    对于一个点,向一段区间内所有点连边

    边数是(O(n^2))

    复杂度爆炸

    于是就有了线段树优化连边......

    线段树优化连边,利用到线段树的思想.

    对于每个区间,新建一个节点,向子区间递归连边.

    这样,当连向一段区间,就等于连向了所有其子节点

    十分抽象.

    看几道例题

    [luogu 5025] [SNOI2017]炸弹

    题目链接

    题解

    暴力做法很显然

    连完边后跑(tarjan + DAG dp)

    然后,线段树优化连边

    Code

    #include<bits/stdc++.h>
    
    #define LL long long
    #define RG register
    
    using namespace std;
    template<class T> inline void read(T &x) {
    	x = 0; RG char c = getchar(); bool f = 0;
    	while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
    	while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
    	x = f ? -x : x;
    	return ;
    }
    template<class T> inline void write(T x) {
    	if (!x) {putchar(48);return ;}
    	if (x < 0) x = -x, putchar('-');
    	int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
    	for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
    }
    
    const int N = 500010, M = 20000010, Mod = 1000000007;
    
    int n, num[N << 2], isleaf[N << 2], tot;
    
    #define ls (rt << 1)
    #define rs (rt << 1 | 1)
    
    struct node {
    	int to, nxt;
    }g[M];
    int last[N << 2], gl, L[N], R[N];
    void add(int x, int y) {
    	g[++gl] = (node) {y, last[x]};
    	last[x] = gl;
    	return ;
    }
    
    struct Segment_Tree {	
    	void build(int rt, int l, int r) {
    		tot = max(tot, rt);
    		if (l == r) {
    			isleaf[rt] = 1;
    			num[l] = rt;
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		add(rt, ls); add(rt, rs);
    		build(ls, l, mid), build(rs, mid + 1, r);
    		return ;
    	}
    	void link(int rt, int l, int r, int L, int R, int id) {
    		if (L <= l && r <= R) {
    			add(id, rt);
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		if (L <= mid) link(ls, l, mid, L, R, id);
    		if (R > mid) link(rs, mid + 1, r, L, R, id);
    		return ;
    	}
    }T;
    
    LL x[N], y[N];
    int dfn[N << 2], low[N << 2], cnt, color[N << 2], C, val[N << 2];
    bool in[N << 2];
    
    stack<int> s;
    
    void tarjan(int u) {
    	dfn[u] = low[u] = ++cnt;
    	in[u] = 1;
    	s.push(u);
    	for (int i = last[u]; i; i = g[i].nxt) {
    		int v = g[i].to;
    		if (!dfn[v]) {
    			tarjan(v);
    			low[u] = min(low[u], low[v]);
    		}
    		else if (in[v]) low[u] = min(low[u], dfn[v]);
    	}
    	if (dfn[u] == low[u]) {
    		C++;
    		while (in[u]) {
    			color[s.top()] = C;
    			val[C] += isleaf[s.top()];
    			in[s.top()] = 0;
    			s.pop();
    		}
    	}
    	return ;
    }
    
    int dp[N << 2];
    
    vector<int> G[N << 2];
    
    inline int dfs(int u) {
    	if (dp[u]) return dp[u];
    	dp[u] = val[u];
    	for (int i = 0; i < (int) G[u].size(); i++) {
    		int v = G[u][i];
    		dp[u] += dfs(v);
    	}
    	return dp[u];
    }
    
    int main() {
    	read(n);
    	for (int i = 1; i <= n; i++)
    		read(x[i]), read(y[i]);
    	for (int i = 1; i <= n; i++) {
    		L[i] = lower_bound(x + 1, x + 1 + n, x[i] - y[i]) - x;
    		R[i] = upper_bound(x + 1, x + 1 + n, x[i] + y[i]) - x - 1;
    	}
    	T.build(1, 1, n);
    	for (int i = 1; i <= n; i++)
    		T.link(1, 1, n, L[i], R[i], num[i]);
    	for (int i = 1; i <= tot; i++)
    		if (!dfn[i]) tarjan(i);
    	for (int i = 1; i <= tot; i++)
    		for (int j = last[i]; j; j = g[j].nxt) {
    			int v = g[j].to;
    			if (color[i] == color[v]) continue;
    			G[color[i]].push_back(color[v]);
    		}
    	for (int i = 1; i <= C; i++) {
    		sort(G[i].begin(), G[i].end());
    		G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
    	}
    	for (int i = 1; i <= C; i++)
    		if (!dp[i])
    			dfs(i);
    	LL ans = 0;
    	for (int i = 1; i <= n; i++)
    		(ans += 1ll * i * dp[color[num[i]]]) %= Mod;
    	write(ans);
    	return 0;
    }
    
    

    看完这题后,应该对于线段树优化连边有了个大概..

    然后看一道稍微难一点的.

    BZOJ3073 Journeys

    权限题警告

    题目描述

    Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路。N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路。Seter保证一条道路不会修建两次,也保证不会有一个国家与自己之间有道路。 Seter好不容易建好了所有道路,他现在在位于P号的首都。Seter想知道P号国家到任意一个国家最少需要经过几条道路。当然,Seter保证P号国家能到任意一个国家。

    注意:可能有重边

    题解

    这回有两个区间了怎么办?

    不能对于(a,b)每个点连区间吧..

    我们弄两棵线段树

    对于每个点,一棵树管出边,另一棵管入边

    线段树里面的边长度都为(0)

    两棵线段树对应点之间连(0)的边

    至于为什么要两棵线段树,

    想想第一题,我们线段树之中的边只能控制一个方向(如果双向边,那两点距离不就变成(0)了)?

    因为第一题是点连向区间,所以只要一个线段树来控制区间

    然而,这题是区间连向区间

    所以我们需要两棵线段树

    然后考虑加边,

    因为两个区间都被分成了很多段

    我们不能每段两两连边

    那么我们可以新建一个节点来整合区间

    具体实现看代码

    Code

    #include<bits/stdc++.h>
    
    #define LL long long
    #define RG register
    
    using namespace std;
    template<class T> inline void read(T &x) {
    	x = 0; RG char c = getchar(); bool f = 0;
    	while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
    	while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
    	x = f ? -x : x;
    	return ;
    }
    template<class T> inline void write(T x) {
    	if (!x) {putchar(48);return ;}
    	if (x < 0) x = -x, putchar('-');
    	int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
    	for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
    }
    
    int n, m, p, tot;
    
    const int N = 2000010;
    
    struct node {
    	int ls, rs;
    }t[N << 2];
    
    struct Graph {
    	int to, nxt, w;
    }g[N * 5];
    int last[N << 1], gl, pos[N];
    inline void add(int x, int y, int z) {
    	g[++gl] = (Graph) {y, last[x], z};
    	last[x] = gl;	
    }
    
    inline void build1(int &rt, int l, int r) {
    	rt = ++tot;
    	if (l == r) {
    		pos[l] = rt;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build1(t[rt].ls, l, mid), build1(t[rt].rs, mid + 1, r);
    	add(t[rt].ls, rt, 0), add(t[rt].rs, rt, 0);
    	return ;
    }
    
    inline void build2(int &rt, int l, int r) {
    	rt = ++tot;
    	if (l == r) {
    		add(rt, pos[l], 0);
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build2(t[rt].ls, l, mid), build2(t[rt].rs, mid + 1, r);
    	add(rt, t[rt].ls, 0), add(rt, t[rt].rs, 0);
    	return ;
    }
    
    inline void link1(int rt, int l, int r, int L, int R) {
    	if (L <= l && r <= R) {
    		add(rt, tot, 1);
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (L <= mid)
    		link1(t[rt].ls, l, mid, L, R);
    	if (R > mid)
    		link1(t[rt].rs, mid + 1, r, L, R);
    	return ;
    }
    
    inline void link2(int rt, int l, int r, int L, int R) {
    	if (L <= l && r <= R) {
    		add(tot, rt, 1);
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (L <= mid)
    		link2(t[rt].ls, l, mid, L, R);
    	if (R > mid)
    		link2(t[rt].rs, mid + 1, r, L, R);
    	return ;
    }
    
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > >q;
    
    int dis[N << 1];
    bool vis[N << 1];
    
    void dijkstra() {
    	memset(dis, 127/3, sizeof(dis));
    	dis[pos[p]] = 0;
    	q.push(make_pair(0, pos[p]));
    	while (!q.empty()) {
    		while (vis[q.top().second] && !q.empty()) q.pop();
    		if (q.empty()) break;
    		int u = q.top().second; q.pop();
    		vis[u] = 1;
    		for (RG int i = last[u]; i; i = g[i].nxt) {
    			int v = g[i].to;
    			if (dis[v] > dis[u] + g[i].w) {
    				dis[v] = dis[u] + g[i].w;
    				q.push(make_pair(dis[v], v));
    			}
    		}
    	}
    	return ;
    }
    
    int main() {
    	read(n), read(m), read(p);
    	int rt1, rt2;
    	rt1 = rt2 = 0;
    	build1(rt1, 1, n); build2(rt2, 1, n);
    	while (m--) {
    		int a, b, c, d;
    		read(a), read(b), read(c), read(d);
    		++tot; link1(rt1, 1, n, a, b); link2(rt2, 1, n, c, d);
    		++tot; link1(rt1, 1, n, c, d); link2(rt2, 1, n, a, b);
    	}
    	dijkstra();
    	for (int i = 1; i <= n; i++)
    		printf("%d
    ", dis[pos[i]] / 2);
    	return 0;
    }
    
    
  • 相关阅读:
    Win7安装netbeans 找不到JDK
    MyEclipse10 中设置Jquery提醒,亲测可用
    Property 'submit' of object #<HTMLFormElement> is not a function
    JSP Unable to compile class for JSP
    JSP session过期时间(小记)
    JSP乱码(小记)
    JS 正则表达式基础
    CSS 盒子模型
    Cmder--window开发者神器!!
    encodeURI和encodeURIComponent两者的区别
  • 原文地址:https://www.cnblogs.com/zzy2005/p/10473443.html
Copyright © 2020-2023  润新知