有的時候,
對於乙個點,向一段區間內所有點連邊
邊數是\(o(n^2)\)的
複雜度**
於是就有了線段樹優化連邊......
線段樹優化連邊,利用到線段樹的思想.
對於每個區間,新建乙個節點,向子區間遞迴連邊.
這樣,當連向一段區間,就等於連向了所有其子節點
十分抽象.
看幾道例題
題目鏈結
暴力做法很顯然
連完邊後跑\(tarjan + dag dp\)
然後,線段樹優化連邊
#include#define ll long long
#define rg register
using namespace std;
templateinline void read(t &x)
templateinline void write(t x)
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 g[m];
int last[n << 2], gl, l[n], r[n];
void add(int x, int y) ;
last[x] = gl;
return ;
}struct segment_tree
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)
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];
stacks;
void tarjan(int u)
else if (in[v]) low[u] = min(low[u], dfn[v]);
} if (dfn[u] == low[u])
} return ;
}int dp[n << 2];
vectorg[n << 2];
inline int dfs(int u)
return dp[u];
}int main()
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)
for (int i = 1; i <= c; i++)
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;
}
看完這題後,應該對於線段樹優化連邊有了個大概..
然後看一道稍微難一點的.
許可權題警告
題目描述
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\)了)?
因為第一題是點連向區間,所以只要乙個線段樹來控制區間
然而,這題是區間連向區間
所以我們需要兩棵線段樹
然後考慮加邊,
因為兩個區間都被分成了很多段
我們不能每段兩兩連邊
那麼我們可以新建乙個節點來整合區間
具體實現看**
#include#define ll long long
#define rg register
using namespace std;
templateinline void read(t &x)
templateinline void write(t x)
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 t[n << 2];
struct graph g[n * 5];
int last[n << 1], gl, pos[n];
inline void add(int x, int y, int z) ;
last[x] = gl;
}inline void build1(int &rt, int l, int r)
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)
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)
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)
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, vector>, greater> >q;
int dis[n << 1];
bool vis[n << 1];
void dijkstra()
} }return ;
}int main()
dijkstra();
for (int i = 1; i <= n; i++)
printf("%d\n", dis[pos[i]] / 2);
return 0;
}
題解 Journeys 線段樹優化連邊
這張圖太直觀了,直接講透了線段樹優化連邊的原理和正確性。考慮建立兩顆線段樹,一顆是外向樹,一顆是內向樹,相當於網路流建模一樣,我們可以利用這兩顆線段樹分別模擬乙個點的入度和出度。畢竟乙個點如果確定了它的入度和出度就相當於確定了在圖中的位置。一條邊進入了乙個父親節點,相當於能進入它所有的兒子,這就模擬...
線段樹優化建邊
完整 總結例題 車站分級 這道題乍一看就能想到等級低的向等級高的連邊,即兩停靠站之間的站點向兩車站連邊,最後跑一遍拓撲排序找出最大值即為答案。以題目樣例為例,假設火車經過站點如下,其中藍色代表停靠,紅色代表不停靠 也就是說,2的等級一定比1 3 5和6低,4的等級一定比1 3 5和6低,建邊如下 拓...
線段樹優化建邊
對於許多的圖論題,有些題可能會出現結點要與區間內的每個點都進行建邊,但是如果進行遍歷建邊,那麼複雜度可能會被卡到 o n 2 此時線段樹的騷操作就出來了。我們知道線段樹的每個結點就是乙個區間,那麼我們就可以把點與區間建邊轉換為點與線段樹上的結點進行連邊。以下是幾道線段樹優化建邊的題目幫助您理解這個思...