對於許多的圖論題,有些題可能會出現結點要與區間內的每個點都進行建邊,但是如果進行遍歷建邊,那麼複雜度可能會被卡到\(o(n^2)\),此時線段樹的騷操作就出來了。
我們知道線段樹的每個結點就是乙個區間,那麼我們就可以把點與區間建邊轉換為點與線段樹上的結點進行連邊。
以下是幾道線段樹優化建邊的題目幫助您理解這個思想。
傳送門在乙個有\(n\)個星球的宇宙中,你現在在編號為\(s\)的星球上,有q種移動到其他星球上的方式,大致分為以下三種型別:
現在問你從\(s\)到每個星球上的最小花費是多少,如果無法達到某個星球那麼這個結點的花費輸出\(-1\).
我們用兩棵線段樹來輔助建邊,一棵從下往上進行建邊(記為\(a\)),一棵從上往下建邊(b)。
對於第一種型別直接連邊即可,第二種型別\(u\)與\(b\)上\([l,r]\)這個區間對應的線段樹結點連邊,第三種型別則是\(a\)上\([l,r]\)對應的結點與\(u\)連邊。
最後跑最短路即可。
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;
typedef long long ll;
typedef pairpll;
typedef pairpli;
typedef pairpil;;
typedef pairpii;
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"=["struct node segtree[5][maxn<<2];
void build(int rt, int l, int r, int op) else );
}return;
}int mid = (l + r) >> 1;
build(lson, l, mid, op); build(rson, mid + 1, r, op);
if(op == 1) );
g[segtree[op][rson].num].push_back();
} else );
g[segtree[op][rt].num].push_back();
}}void update(int rt, int l, int r, int u, int w, int op) );
} else );
}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
}void dij(int s) );
while(!q.empty()) );}}
}}int main());
} else
}dij(s);
for(int i = 1; i <= n; ++i)
printf("\n");
return 0;
}
傳送門
給你\(n\)個數,要將這\(n\)個數放進\(hash\)表中。放置的規則為:將\(a_i\)進行\(hash\),假設第\(i\)個數對應的值為\(a_i\),那麼它對應的\(hash\)值為\(a_i\%n\)。如果它的\(hash\)值對應的位置沒有放數,那麼就將這個數放到這個位置;否則就往後移,一直到可以放進去為止。現在給你已經放完的\(hash\)表,問你放數的順序。
我們對於每個數\(a_i\),如果它沒有放在它對應的\(hash\)值的位置上,假設當前的位置為\(pos\),那麼易知\([a_i\% hash,pos-1]\)上的數都是在這個數之前放進來的。因此我們可以用線段樹進行優化建邊然後跑一遍拓撲排序,如果得到的結點數小於原來非\(-1\)的個數那麼就輸出\(-1\),否則輸出字典序最小的構造方法(優先佇列替換拓撲排序中的佇列)。
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;
typedef long long ll;
typedef pairpll;
typedef pairpli;
typedef pairpil;;
typedef pairpii;
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"=["int a[maxn], vis[maxn*10], in[maxn*10], dd[maxn];
struct node segtree[maxn<<2];
void build(int rt, int l, int r)
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)
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 }
int main()
}if(num == 0)
cnt = 0;
v.clear();
build(1, 1, n);
priority_queue, greater> q;
for(int i = 1; i <= n; ++i) );
} else if(t > i - 1) else
}int u;
while(!q.empty())
for(int i = 0; i < (int)g[u].size(); ++i) );
else q.push();}}
}if(v.size() == num)
} else
for(int i = 0; i <= cnt; ++i)
}return 0;
}
線段樹優化建邊
完整 總結例題 車站分級 這道題乍一看就能想到等級低的向等級高的連邊,即兩停靠站之間的站點向兩車站連邊,最後跑一遍拓撲排序找出最大值即為答案。以題目樣例為例,假設火車經過站點如下,其中藍色代表停靠,紅色代表不停靠 也就是說,2的等級一定比1 3 5和6低,4的等級一定比1 3 5和6低,建邊如下 拓...
線段樹優化連邊
有的時候,對於乙個點,向一段區間內所有點連邊 邊數是 o n 2 的 複雜度 於是就有了線段樹優化連邊.線段樹優化連邊,利用到線段樹的思想.對於每個區間,新建乙個節點,向子區間遞迴連邊.這樣,當連向一段區間,就等於連向了所有其子節點 十分抽象.看幾道例題 題目鏈結 暴力做法很顯然 連完邊後跑 tar...
車站分級 (線段樹優化建邊 拓撲序最長路)
10.11 思路 基本方法就是等級高的車站向等級低的車站連邊,最後跑拓撲序的最長路就是ans。線段樹優化建邊的拓撲排序 線段樹的神奇應用 先是建虛點優化,邊數優化為2 n,但是發現建邊的複雜度是nm,考慮線段樹優化。注意到經停站把車站序列劃分成了多個區間,每個區間對應o log 個線段樹上的節點,因...