线段树优化建图

线段树优化建图

  • 这是一个十分经典的\(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]]);
    }
    
}

    
posted @ 2022-10-14 00:00  kiritokazuto  阅读(41)  评论(0编辑  收藏  举报