线段树优化建图
线段树优化建图
- 这是一个十分经典的\(trick\)了
- 对于那种\(n ^ {2}\)建图的题,可以通过这个把复杂度降下来,其实就是把那些需要给每个点连的边连到区间上,化为\(\log\)段。
- 具体来讲,我们可以建造两棵线段树
- 一棵叫入树,由叶子节点向根节点连边。
- 一颗叫出树,由根节点向叶子节点连边。
- 其实就是一棵处理起点,另一棵处理终点。注意这两棵树的边的方向不能反,否则就会寄掉。(会访问其他的位置)
- 对于这两棵树内部的边是边权为\(0\)的(因为大区间实际上是小单点的叠加),对于他们的叶子节点之间,也需要建造边权为\(0\)的边(因为实际上他们是同一个点)
- 其他的就从入树向出树连你需要的边就好了,实际上是个单点操作。
例题的话有一个板子Legacy
here
#include <bits/stdc++.h>
#define LL long long
#define Re register int
#define LD double
#define mes(x, y) memset(x, y, sizeof(x))
#define fuc(x, y) inline x y
#define fr(x, y, z)for(Re x = y; x <= z; ++ x)
#define fp(x, y, z)for(Re x = y; x >= z; -- x)
#define delfr(x, y, z)for(Re x = y; x < z; ++ x)
#define delfp(x, y, z)for(Re x = y; x > z; -- x)
#define frein(x) freopen(#x ".in", "r", stdin)
#define freout(x) freopen(#x ".out", "w", stdout)
#define ki putchar('\n')
#define fk putchar(' ')
#define WMX aiaiaiai~~
#define mk(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define sec second
#define fst first
using namespace std;
namespace kiritokazuto{
// auto read = [](){
// LL x = 0;
// int f = 1;
// char c;
// while (!isdigit(c = getchar())){ if (c == '-')f = -1; }
// do{ x = (x << 1) + (x << 3) + (c ^ 48); } while (isdigit(c = getchar()));
// return x * f;
// };
inline char getc(){
static char buf[1<<18],*p1,*p2;
if(p1==p2){p1=buf,p2=buf+fread(buf,1,1<<18,stdin);if(p1==p2)return EOF;}
return *p1++;
}
inline LL read(){
LL x=0;char ch=getc();
while(!isdigit(ch))ch=getc();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getc();
return x;
}
template <typename T> fuc(void, write) (T x){
if (x < 0)putchar('-'), x = -x;
if (x > 9)write(x / 10);putchar(x % 10 | '0');
}
}
using namespace kiritokazuto;
const int maxn = 1e5 + 200, Inf = 0x3f3f3f3f, Mod = 5000007;
#define int long long
int head[maxn * 10], len = 0;
int n, Q, s;
struct Node {int to, next; LL dis;Node(){}; Node(int x, LL y, int z){to = x, dis = y, next = z;}}wmx[maxn * 30];
fuc(void, Qian)(int from, int to, LL dis){wmx[++len] = (Node){to, dis, head[from]}; head[from] = len;}
struct D{int pos;LL val;friend bool operator < (D A, D B){return A.val > B.val;}};
int vis[maxn * 30];
LL dis[maxn * 30];
int in[maxn * 30], out[maxn * 30];
int lsp[maxn * 30], rsp[maxn * 30], tot;
int rt1, rt2;
struct Seg_Tree {
#define mid ((l + r) >> 1)
fuc(void, build_in)(int &rt, int l, int r) {
rt = ++tot;
if(l == r) return in[l] = rt, void();
build_in(lsp[rt], l, mid);build_in(rsp[rt], mid + 1, r);Qian(lsp[rt], rt, 0);Qian(rsp[rt], rt, 0);
}
fuc(void, build_out)(int &rt, int l, int r) {
rt = ++tot;
if(l == r) return out[l] = rt, void();
build_out(lsp[rt], l, mid);build_out(rsp[rt], mid + 1, r);Qian(rt, lsp[rt], 0);Qian(rt, rsp[rt], 0);
}
fuc(void, insert_in)(int rt, int l, int r, int L, int R, int pos, LL val) {
if(L <= l && r <= R) return Qian(rt, pos, val),void();//入树区间向出树节点连
if(L <= mid)insert_in(lsp[rt], l, mid, L, R, pos, val);
if(R > mid)insert_in(rsp[rt], mid + 1, r, L, R, pos, val);
}
fuc(void, insert_out)(int rt, int l, int r, int L, int R, int pos, LL val) {
if(L <= l && r <= R) return Qian(pos, rt, val),void();//入树点向出树区间连
if(L <= mid)insert_out(lsp[rt], l, mid, L, R, pos, val);
if(R > mid)insert_out(rsp[rt], mid + 1, r, L, R, pos, val);
}
}T;
fuc(void, Dij)(int st) {
mes(dis, 0x3f);
priority_queue<D> q;
q.push(D{in[st], 0});
dis[in[st]] = 0;
while(!q.empty()) {
int pos = q.top().pos;
q.pop();
if(vis[pos])continue;
vis[pos] = 1;
for(Re i = head[pos]; i; i = wmx[i].next) {
int to = wmx[i].to;
if(dis[to] > dis[pos] + wmx[i].dis){
dis[to] = dis[pos] + wmx[i].dis;
// if(vis[to]) continue;
q.push(D{to, dis[to]});
}
}
}
}
signed main(){
n = read(), Q = read(), s = read();
T.build_in(rt1, 1, n);
T.build_out(rt2, 1, n);
fr(i, 1, n) {
Qian(in[i], out[i], 0);
Qian(out[i], in[i], 0);
}
fr(i, 1, Q) {
int opt = read();
switch(opt) {
case 1 : {//v到u单向
LL v = read(), u = read(), w = read();
Qian(in[v], out[u], w);
break;
}
case 2 : {//v到[l,r]单向
LL v = read(), l = read(), r = read(), w = read();
T.insert_out(rt2, 1, n, l, r, in[v], w);
break;
}
case 3 : {//[l, r]到v单向
LL v = read(), l = read(), r = read(), w = read();
T.insert_in(rt1, 1, n, l, r, out[v], w);
break;
}
}
}
// cerr << "here" << "\n";
Dij(s);
// cerr << "Here" << "\n";
fr(i, 1, n) {
if(dis[out[i]] == dis[0]) {
printf("-1 ");continue;
}else printf("%lld ", dis[out[i]]);
}
}
愿你在冷铁卷刃之前,得以窥见天光