CF786B Legacy
好久没有看到这样让人惊叹的建图方法了, 需要记录一下这个线段树优化建图的思路.
这位大佬 讲的已经很好了, 看他的就行.
其实这一题本质上就是用增加 \(logN\) 级别的点的代价将 \(O(N^2)\) 时间的建边优化到 \(O(NlogN)\) , 的确是线段树的思想.
开两颗线段树是防止冲突. 的确很妙.
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5 + 10;
inline int read(){
char ch = getchar(); int x = 0;
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
int N, Q, S;
struct edge
{
int to, cost;
};vector<edge> g[MAXN << 2];
namespace stree
{
#define mid ((l + r) >> 1)
struct Node
{
int ls, rs;
}node[MAXN << 2];
int rootin, rootout;
int pos;
void build(int &o, int l, int r, bool Type) {
if(l == r) return o = l, void();
o = ++pos;
build(node[o].ls, l, mid, Type),
build(node[o].rs, mid + 1, r, Type);
if(Type) {
g[o].push_back((edge) {node[o].ls, 0}),
g[o].push_back((edge) {node[o].rs, 0});
}
else {
g[node[o].ls].push_back((edge) {o, 0});
g[node[o].rs].push_back((edge) {o, 0});
}
}
void modify(int &o, int l, int r, int a, int b, int u, int c, bool Type) {
if(l > b || r < a) return ;
if(a <= l && r <= b) {
if(Type) g[u].push_back((edge) {o, c});
else g[o].push_back((edge) {u, c});
return;
}
modify(node[o].ls, l, mid, a, b, u, c, Type);
modify(node[o].rs, mid + 1, r, a, b, u, c, Type);
}
#undef mid
}
inline bool tension(const ll st, ll &lg) {
return lg > st ? (lg = st, true) : false;
}
ll dis[MAXN << 2];
void dijkstra() {
priority_queue<P, vector<P>, greater<P> > q;
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0, q.push(P(0, S));
while(!q.empty()) {
P p = q.top(); q.pop();
int u = p.second;
if(dis[u] < p.first) continue;
for(int i = 0; i < (int) g[u].size(); i++) {
edge &e = g[u][i];
if(tension(dis[u] + e.cost, dis[e.to]))
q.push(P(dis[e.to], e.to));
}
}
}
int main(){
cin>>N>>Q>>S;
using namespace stree;
pos = N; build(rootin, 1, N, true), build(rootout, 1, N, false);
while(Q--) {
int opt = read();
if(opt == 1) {
int u = read(), v = read(), c = read();
g[u].push_back((edge) {v, c});
}
else if(opt == 2) {
int u = read(), l = read(), r = read(), c = read();
modify(rootin, 1, N, l, r, u, c, true);
}
else {
int u = read(), l = read(), r = read(), c = read();
modify(rootout, 1, N, l, r, u, c, false);
}
}
dijkstra();
for(int i = 1; i <= N; i++)
cout<<(dis[i] == INF ? -1 : dis[i])<<" ";
return 0;
}