对于许多的图论题,有些题可能会出现结点要与区间内的每一个点都进行建边,可是若是进行遍历建边,那么复杂度可能会被卡到$O(n^2)$,此时线段树的骚操做就出来了。 咱们知道线段树的每一个结点就是一个区间,那么咱们就能够把点与区间建边转换为点与线段树上的结点进行连边。 如下是几道线段树优化建边的题目帮助您理解这个思想。node
Legacy (CodeForces - 787D)
题目连接
传送门ios
题意
在一个有$n$个星球的宇宙中,你如今在编号为$s$的星球上,有q种移动到其余星球上的方式,大体分为如下三种类型:c++
- $u$星球到$v$星球,花费为$w$;
- $u$星球到$[L,R]$区间内的某一个星球,花费为$w$;
- $[L,R]$区间内的某个星球到$u$星球,花费为$w$.
如今问你从$s$到每一个星球上的最小花费是多少,若是没法达到某个星球那么这个结点的花费输出$-1$.优化
思路
咱们用两棵线段树来辅助建边,一棵从下往上进行建边(记为$A$),一棵从上往下建边(B)。 对于第一种类型直接连边便可,第二种类型$u$与$B$上$[L,R]$这个区间对应的线段树结点连边,第三种类型则是$A$上$[L,R]$对应的结点与$u$连边。 最后跑最短路便可。ui
代码实现以下
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("D://code//in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 1e5 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; LL dis[maxn*15]; int n, q, s, cnt, op, u, l, r, w, v; int pp1[maxn], pp2[maxn], vis[maxn * 15]; struct edge { int v, w; }; vector<edge> G[maxn * 15]; struct node { int l, r, num; }segtree[5][maxn<<2]; void build(int rt, int l, int r, int op) { segtree[op][rt].l = l, segtree[op][rt].r = r; segtree[op][rt].num = ++cnt; if(l == r) { if(op == 1) { pp1[l] = cnt; } else { pp2[l] = cnt; G[pp2[l]].push_back({pp1[l], 0}); } return; } int mid = (l + r) >> 1; build(lson, l, mid, op); build(rson, mid + 1, r, op); if(op == 1) { G[segtree[op][lson].num].push_back({segtree[op][rt].num, 0}); G[segtree[op][rson].num].push_back({segtree[op][rt].num, 0}); } else { G[segtree[op][rt].num].push_back({segtree[op][lson].num, 0}); G[segtree[op][rt].num].push_back({segtree[op][rson].num, 0}); } } void update(int rt, int l, int r, int u, int w, int op) { if(segtree[op][rt].l == l && segtree[op][rt].r == r) { if(op == 1) { G[u].push_back({segtree[2][rt].num, w}); } else { G[segtree[1][rt].num].push_back({u, w}); } return; } int mid = (segtree[op][rt].l + segtree[op][rt].r) >> 1; if(r <= mid) update(lson, l, r, u, w, op); else if(l > mid) update(rson, l, r, u, w, op); else { update(lson, l, mid, u, w, op); update(rson, mid + 1, r, u, w, op); } } void dij(int s) { for(int i = 1; i <= cnt; ++i) dis[i] = INF; dis[pp1[s]] = 0; priority_queue<pLi, vector<pLi>, greater<pLi> > q; q.push({0, pp1[s]}); while(!q.empty()) { int u = q.top().second; q.pop(); if(vis[u]) continue; vis[u] = 1; int v; for(int i = 0; i < (int)G[u].size(); ++i) { v = G[u][i].v; if(dis[v] > dis[u] + G[u][i].w) { dis[v] = dis[u] + G[u][i].w; q.push({dis[v], v}); } } } } int main(){ #ifndef ONLINE_JUDGE FIN; #endif scanf("%d%d%d", &n, &q, &s); for(int i = 1; i <= 2; ++i) build(1, 1, n, i); while(q--) { scanf("%d", &op); if(op == 1) { scanf("%d%d%d", &u, &v, &w); G[pp1[u]].push_back({pp2[v], w}); } else { op--; scanf("%d%d%d%d", &u, &l, &r, &w); if(op == 1) update(1, l, r, pp1[u], w, op); else update(1, l, r, pp2[u], w, op); } } dij(s); for(int i = 1; i <= n; ++i) { LL tmp = min(dis[pp1[i]], dis[pp2[i]]); if(tmp == INF) printf("-1 "); else printf("%lld ", tmp); } printf("\n"); return 0; }
Hash Function
题目连接
传送门url
题目大意
给你$n$个数,要将这$n$个数放进$hash$表中。放置的规则为:将$a_i$进行$hash$,假设第$i$个数对应的值为$a_i$,那么它对应的$hash$值为$a_i%n$。若是它的$hash$值对应的位置没有放数,那么就将这个数放到这个位置;不然就日后移,一直到能够放进去为止。如今给你已经放完的$hash$表,问你放数的顺序。spa
思路
咱们对于每一个数$a_i$,若是它没有放在它对应的$hash$值的位置上,假设当前的位置为$pos$,那么易知$[a_i% hash,pos-1]$上的数都是在这个数以前放进来的。所以咱们能够用线段树进行优化建边而后跑一遍拓扑排序,若是获得的结点数小于原来非$-1$的个数那么就输出$-1$,不然输出字典序最小的构造方法(优先队列替换拓扑排序中的队列)。.net
代码实现以下
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #include <bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> piL;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("in","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1e9 + 7; const int maxn = 2e5 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; int t, n, cnt; vector<int> v, G[maxn*10]; int a[maxn], vis[maxn*10], in[maxn*10], dd[maxn]; struct node { int l, r, num; }segtree[maxn<<2]; void build(int rt, int l, int r) { segtree[rt].l = l, segtree[rt].r = r; segtree[rt].num = ++cnt; in[segtree[rt].num] = 2; if(l == r) { in[cnt] = 0; dd[l] = cnt; vis[cnt] = l; return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); G[segtree[lson].num].push_back(segtree[rt].num); G[segtree[rson].num].push_back(segtree[rt].num); } void update(int rt, int l, int r, int u) { if(segtree[rt].l == l && segtree[rt].r == r) { G[segtree[rt].num].push_back(u); in[u]++; return; } int mid = (segtree[rt].l + segtree[rt].r) >> 1; if(r <= mid) update(lson, l, r, u); else if(l > mid) update(rson, l, r, u); else { update(lson, l, mid, u); update(rson, mid + 1, r, u); } } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%d", &t); while(t--) { scanf("%d", &n); int num = 0; for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); if(a[i] != -1) { num++; } } if(num == 0) { printf("\n"); continue; } cnt = 0; v.clear(); build(1, 1, n); priority_queue<pii, vector<pii>, greater<pii> > q; for(int i = 1; i <= n; ++i) { if(a[i] == -1) continue; int t = a[i] % n; if(t == i - 1) { q.push({a[i], dd[i]}); } else if(t > i - 1) { update(1, t + 1, n, dd[i]); if(i >= 2) update(1, 1, i - 1, dd[i]); } else { if(t + 1 <= i - 1) update(1, t + 1, i - 1, dd[i]); } } int u; while(!q.empty()) { u = q.top().second; q.pop(); if(vis[u] != 0) { v.push_back(vis[u]); } for(int i = 0; i < (int)G[u].size(); ++i) { int v = G[u][i]; if(--in[v] == 0) { if(vis[v]) q.push({a[vis[v]], v}); else q.push({0, v}); } } } if(v.size() == num) { for(int i = 0; i < (int)v.size(); ++i) { printf("%d%c", a[v[i]], i == (int)v.size() - 1 ? '\n' : ' '); } } else { printf("-1\n"); } for(int i = 0; i <= cnt; ++i) { vis[i] = in[i] = 0; G[i].clear(); } } return 0; }