對於許多的圖論題,有些題可能會出現結點要與區間內的每一個點都進行建邊,可是若是進行遍歷建邊,那麼複雜度可能會被卡到$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; }