CF786B Legacy (线段树优化建边)
线段树优化建边。
首先 \(O(n^2)\) 建边会 \(MLE\),于是考虑优化。对于区间建边,我们可以用线段树优化建边。本质是用线段树上延迟标记的性质,可以先把边建在更大的节点上。
具体的,考虑维护两棵线段树,第一颗父亲向儿子连 \(0\) 边,表示大区间到小区间无代价,维护入边信息;第二颗儿子向父亲连边,表示小区间可以到大区间无代价,维护出边信息;两棵线段树的对于叶子节点也应连边,本质是同一个点。
对于操作 \(1\),任意两个叶子节点连边即可。
对于操作 \(2\),任意一棵的叶子结点连向第一棵的 \(\log n\) 个区间。
对于操作 \(3\),第二颗的 \(\log n\) 个区间连向任意一棵的叶子结点。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read(){
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c - '0');
c = getchar();
}
return x * f;
}
int n, q, S;
int sum, cnt;
int a[3000010], w[100010 << 2];
int h[3000010], dis[3000010], vis[3000010];
struct node{
int to, nxt, w;
}e[3000100];
void add(int u, int v, int w){
e[++cnt].to = v;
e[cnt].nxt = h[u];
e[cnt].w = w;
h[u] = cnt;
}
void build(int u, int l, int r){
sum = max(sum, u);
if(l == r){
a[l] = u;
return;
}
int mid = (l + r) >> 1;
add(u, u << 1, 0);
add(u, u << 1 | 1, 0);
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
void build2(int u, int l, int r){
if(l == r){
return;
}
int mid = (l + r) >> 1;
add((u << 1) + sum, u + sum, 0);
add((u << 1 | 1) + sum, u + sum, 0);
build2(u << 1, l, mid), build2(u << 1 | 1, mid + 1, r);
}
bool inrange(int l, int r, int L, int R){
return (L <= l) && (r <= R);
}
void update(int u, int l, int r, int L, int R, int w, int v){
if(inrange(l, r, L, R)){
add(a[v], u, w);
return;
}
int mid = (l + r) >> 1;
if(L <= mid) update(u << 1, l, mid, L, R, w, v);
if(R > mid) update(u << 1 | 1, mid + 1, r, L, R, w, v);
}
void update2(int u, int l, int r, int L, int R, int w, int v){
if(inrange(l, r, L, R)){
add(u + sum, a[v], w);
return;
}
int mid = (l + r) >> 1;
if(L <= mid) update2(u << 1, l, mid, L, R, w, v);
if(R > mid) update2(u << 1 | 1, mid + 1, r, L, R, w, v);
}
struct com{
int v, w;
friend bool operator < (com a, com b){
return a.w > b.w;
}
}tmp;
void dij(int s){
priority_queue<com> q;
for(int i = 1; i <= sum * 2; i++) dis[i] = 1ll << 62;
dis[s] = 0;
q.push({s, 0});
while(!q.empty()){
int u = q.top().v;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = h[u]; i; i = e[i].nxt){
int v = e[i].to;
if(dis[v] > dis[u] + e[i].w){
dis[v] = dis[u] + e[i].w;
tmp.v = v, tmp.w = dis[v];
q.push(tmp);
}
}
}
}
signed main(){
n = read(), q = read(), S = read();
build(1, 1, n), build2(1, 1, n);
for(int i = 1; i <= n; i++) add(a[i], a[i] + sum, 0), add(a[i] + sum, a[i], 0);
for(int i = 1; i <= q; i++){
int opt, v, l, r, w;
opt = read();
if(opt == 1){
v = read(), l = read(), w = read();
add(a[v], a[l], w);
}
else if(opt == 2){
v = read(), l = read(), r = read(), w = read();
update(1, 1, n, l, r, w, v);
}
else if(opt == 3){
v = read(), l = read(), r = read(), w = read();
update2(1, 1, n, l, r, w, v);
}
}
dij(a[S] + sum);
for(int i = 1; i <= n; i++){
if(dis[a[i]] == 1ll << 62) cout << -1 << " ";
else cout << dis[a[i]] << " ";
}
cout << endl;
return 0;
}