线段树优化建边
P6348 [PA2011]Journeys
线段树可以用来优化一些特殊的建边,特别是n方级别的建边,我们可以建一颗入树, 一颗出树,[a, b]->[c, d],可以借助建造两个虚点完成。

如图所示 左边是入树, 右边是出树, 蓝色边权为0,当我们需要从[a, b]->[c, d]建边可以这样干, 例如[1,2]->[3,4],建立两个虚点。搭建起桥梁,我们可以神奇的发现,这样建边,居然符合条件,这就是线段树的魅力(具体细节看代码吧)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
template <typename T> inline void read(T& t)
{
int f = 0, c = getchar();
t = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
if (f) t = -t;
}
const int N = 5e6 + 10;
int cnt, head[N];
struct edge
{
int to, nex, w;
} e[N << 1];
inline void add(int u, int v, int w)
{
e[++cnt].to = v;
e[cnt].w = w;
e[cnt].nex = head[u];
head[u] = cnt++;
}
int n, m, s;
int tot, Ls[N], Rs[N], In, Out;
void buildIn(int &k, int l, int r)
{
if(l == r)
{
k = l;
return;
}
k = ++tot;
int mid = l + r >> 1;
buildIn(Ls[k], l, mid);
buildIn(Rs[k], mid + 1, r);
add(k, Ls[k], 0);
add(k, Rs[k], 0);
}
void buildOut(int &k, int l, int r)
{
if(l == r)
{
k = l;
return;
}
k = ++tot;
int mid = l + r >> 1;
buildOut(Ls[k], l, mid);
buildOut(Rs[k], mid + 1, r);
add(Ls[k], k, 0);
add(Rs[k], k, 0);
}
void addOut(int k, int l, int r, int L, int R, int idx)
{
if(l >= L && r <= R)
{
add(k, idx, 0);
return;
}
int mid = l + r >> 1;
if(L <= mid) addOut(Ls[k], l, mid, L, R, idx);
if(R > mid) addOut(Rs[k], mid + 1, r, L, R, idx);
}
void addIn(int k, int l, int r, int L, int R, int idx)
{
if(l >= L && r <= R)
{
add(idx, k, 0);
return;
}
int mid = l + r >> 1;
if(L <= mid) addIn(Ls[k], l, mid, L, R, idx);
if(R > mid) addIn(Rs[k], mid + 1, r, L, R, idx);
}
void insertt(int a, int b, int c, int d)
{
int p = ++tot;
addOut(Out, 1, n, a, b, p);
int q = ++tot;
addIn(In, 1, n, c, d, q);
add(p, q, 1);
}
struct v
{
int x;
ll dis;
bool operator < (const v& a) const
{
return dis > a.dis;
}
};
ll dis[N];
bool vis[N];
inline void dijstra()
{
priority_queue<v> q;
memset(dis, 120, sizeof dis);
memset(vis, 0, sizeof vis);
dis[s] = 0;
q.push({s, 0});
while(!q.empty())
{
v now = q.top();
q.pop();
if(vis[now.x]) continue;
vis[now.x] = 1;
for(int i = head[now.x] ; i; i = e[i].nex)
{
int y = e[i].to;
if(dis[y] > dis[now.x] + e[i].w)
{
dis[y] = dis[now.x] + e[i].w;
q.push({y, dis[y]});
}
}
}
}
signed main()
{
read(n), read(m), read(s);
tot = n;
buildIn(In, 1, n);
buildOut(Out, 1, n);
int a, b, c, d;
while(m--)
{
read(a);
read(b);
read(c);
read(d);
insertt(a, b, c, d);
insertt(c, d, a, b);
}
dijstra();
for(int i = 1; i <= n; ++i) printf("%lld\n", dis[i]);
return 0;
}
Legacy
传送门
这道题降低了难度,我们只需要在,入树或者出树上自己操作自己,不需要构建p,q两点,套模板就行
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 2e6 + 10;
int cnt, head[N];
struct edge
{
int to, nex, w;
} e[N << 1];
inline void add(int u, int v, int w)
{
e[++cnt].to = v;
e[cnt].w = w;
e[cnt].nex = head[u];
head[u] = cnt;
}
int n, m, s;
int tot, Ls[N], Rs[N], In, Out;
void buildIn(int &k, int l, int r)
{
if(l == r)
{
k = l;
return;
}
k = ++tot;
int mid = l + r >> 1;
buildIn(Ls[k], l, mid);
buildIn(Rs[k], mid + 1, r);
add(k, Ls[k], 0);
add(k, Rs[k], 0);
}
void buildOut(int &k, int l, int r)
{
if(l == r)
{
k = l;
return;
}
k = ++tot;
int mid = l + r >> 1;
buildOut(Ls[k], l, mid);
buildOut(Rs[k], mid + 1, r);
add(Ls[k], k, 0);
add(Rs[k], k, 0);
}
void addIn(int k, int l, int r, int L, int R, int tag, int w)
{
if(l >= L && r <= R)
{
add(tag, k, w);
return;
}
int mid = l + r >> 1;
if(L <= mid) addIn(Ls[k], l, mid, L, R, tag, w);
if(R > mid) addIn(Rs[k], mid + 1, r, L, R, tag, w);
}
void addOut(int k, int l, int r, int L, int R, int tag, int w)
{
if(l >= L && r <= R)
{
add(k, tag, w);
return;
}
int mid = l + r >> 1;
if(L <= mid) addOut(Ls[k], l, mid, L, R, tag, w);
if(R > mid) addOut(Rs[k], mid + 1, r, L, R, tag, w);
}
struct v
{
int x;
LL dis;
bool operator < (const v& rhs) const
{
return dis > rhs.dis;
}
};
LL dis[N];
bool vis[N];
inline void dijstra()
{
priority_queue<v> q;
memset(dis, 120, sizeof dis);
memset(vis, 0, sizeof vis);
dis[s] = 0;
q.push({s, 0});
while(!q.empty())
{
v now = q.top();
q.pop();
if(vis[now.x]) continue;
vis[now.x] = 1;
for(int i = head[now.x]; i; i = e[i].nex)
{
int y = e[i].to;
if(dis[y] > dis[now.x] + e[i].w)
{
dis[y] = dis[now.x] + e[i].w;
q.push({y, dis[y]});
}
}
}
}
signed main()
{
cin >> n >> m >> s;
tot = n;
buildIn(In, 1, n);
buildOut(Out, 1, n);
int op, l, r, u, v, w;
while(m-- && cin >> op)
{
if(op == 1)
{
cin >> u >> v >> w;
add(u, v, w);
}
else if(op == 2)
{
cin >> u >> l >> r >> w;
addIn(In, 1, n, l, r, u, w);
}
else
{
cin >> u >> l >> r >> w;
addOut(Out, 1, n, l, r, u, w);
}
}
dijstra();
for(int i = 1; i <= n; ++i)
{
if(dis[i] == 8680820740569200760) cout << "-1 ";
else cout << dis[i] << " ";
}
return 0;
}

浙公网安备 33010602011771号