(线段树) 优化建图
图论中形如点向一段区间连边,(或者区间向区间?)的问题。
题意:点向点连边,点向区间连边,区间向点连边,求最短路。
运用区间划分思想,开两颗线段树,一颗存第二种边,一颗存第三种边(注意不能混用!!)
线段树上,区间和所管的子区间连向上或向下的边,边权为 0。
然后原图中每个点对应的就是线段树上的叶子节点,所以线段树间对应的叶子也要连边权为 0 的边。
这样每种边就被拆成了 log 个区间,类似线段树区间修改的方式插入即可。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ull = unsigned long long;
using ldb = long double;
using pii = pair<ll, int>;
#define pb push_back
#define pc putchar
#define sp pc(' ')
#define et pc('\n')
#define debug cerr<<"--ERROR--\n"
#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define per(i, a, b) for(int i = (a); i >= (b); --i)
#define mem(a, x) memset(a, x, sizeof(a))
#define in(a, n) rep(i, 1, n) a[i]=rd()
#define all(x) x.begin(), x.end()
inline ll rd(){ll x=0; int f=1; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-48; c=getchar();} return x*f;}
inline void wr(ll x){if(x<0) putchar('-'), x=-x; static int stk[35]; int tp=0; do stk[tp++]=x%10;while(x/=10); do pc(stk[--tp]^48);while(tp);}
//const ldb eps = 1e-9;
const ll INF = 0x3f3f3f3f3f3f3f3f;
//const int mo = 1e9+7;
const int N = 1e6+3;
const int B = 5e5;
int n, q, S, pos[N], vis[N];
ll dis[N];
vector <pii> g[N];
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
void clear() { }
void add(int u, int v, int w) {
// printf("%d %d %d\n", u, v, w);
g[u].pb({v, w});
}
void build(int p, int l, int r) {
if(l == r) {
pos[l] = p;
add(p, p+B, 0), add(p+B, p, 0);
return ;
}
add(p, ls(p), 0), add(p, rs(p), 0);
add(ls(p)+B, p+B, 0), add(rs(p)+B, p+B, 0);
int mid = l+r>>1;
build(ls(p), l, mid), build(rs(p), mid+1, r);
}
void upd(int p, int l, int r, int x, int y, int u, int w, int op) {
// 1 : [x, y] -> u, 0 : u -> [x, y]
if(l >= x && r <= y) {
if(op) add(p+B, pos[u]+B, w);
else add(pos[u], p, w);
return ;
}
int mid = l+r>>1;
if(x <= mid) upd(ls(p), l, mid, x, y, u, w, op);
if(y > mid) upd(rs(p), mid+1, r, x, y, u, w, op);
}
void dij(int s) {
mem(dis, INF);
dis[s] = 0;
priority_queue <pii> q;
q.push({0, s});
while(!q.empty()) {
int u = q.top().second;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(auto t : g[u]) {
int v = t.first, w = t.second;
if(dis[u]+w < dis[v]) dis[v] = dis[u]+w, q.push({-dis[v], v});
}
}
}
signed main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
int TT = 1;
//TT = rd();
while(TT--)
{
clear();
cin >> n >> q >> S;
build(1, 1, n);
while(q--) {
int op=rd(), x=rd(), y=rd(), z=rd();
if(op == 1) {
add(pos[x], pos[y], z);
}
else {
upd(1, 1, n, y, z, x, rd(), op&1);
}
}
dij(pos[S]);
rep(i, 1, n) wr(dis[pos[i]]==INF ? -1 : dis[pos[i]]), sp;
et;
}
return 0;
}
前后缀、倍增优化等同理

浙公网安备 33010602011771号