CF786B Legacy[线段树优化建图]

Problem


发现可以线段树建图…

线段树建图 大概就是这样子…

众所周知 线段树的一个编号 \(p\) 指的是 \([L,R]\) 这段区间

void buildto(int l , int r , int & p) { // 入边·线段树
    if(l == r) { p = l ; return ; }
    int mid = l + r >> 1 ; p = ++ cnt ;
    buildto(l , mid , ls[p]) ; buildto(mid + 1 , r , rs[p]) ;
    add(p , ls[p] , 0) ; add(p , rs[p] , 0) ;
  }

\(p\) 指的是 \([L,R]\) 这段区间的编号
\(ls_p\) 指的是 \([L,Mid]\) 这段区间的编号
\(rs_p\) 指的是 \([Mid+1,R]\) 这段区间的编号
初始化 \(p\)\(p\) 的左儿子 和 \(p\) 的右儿子连边…

那么就间接完成了 \(p\)\([L,R]\)单独连边

即如果对 \(p\) 连边 就相当于对 \([L,R]\) 连边…

大概解释的够清楚了?
所以这题可以建两颗线段树 一棵管入边 一棵管出边…
最后跑个最短路就出来了…

#include <bits/stdc++.h>
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define rep(i , j , k) for(int i = j ; i <= k ; i ++)
#define Rep(i , j , k) for(int i = j ; i >= k ; i --)
using namespace std ;
using ll = long long ;
using pii = pair <int , int> ;
using vii = vector <int> ;
#define int long long
auto ot = [&]() { cerr << "ATS TXDY" << '\n' ; int ATS_nantf_txdy = true ; } ;
auto _ios = [&]() { ios :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ; } ;
namespace stO_ATS_Orz {
  template < class T > void cmax(T & x , T y) { if(x < y) x = y ; }
  template < class T > void cmin(T & x , T y) { if(x > y) x = y ; }
  template < class T > void abs(T x) { if(x < 0) x = -x ; }
  const int N = 1e5 + 10 ;
  int n , m , s ;
  struct Node { int v , nxt , w ; } e[N * 30] ;
  int rt1 , rt2 , cnt , head[N << 2] , ecnt = 0 , ls[N << 2] , rs[N << 2] , dis[N << 2] , vis[N << 2] ;
  void add(int u , int v , int w) { e[++ ecnt] = {v , head[u] , w} ; head[u] = ecnt ; }
  void buildto(int l , int r , int & p) { // 入边·线段树
    if(l == r) { p = l ; return ; }
    int mid = l + r >> 1 ; p = ++ cnt ;
    buildto(l , mid , ls[p]) ; buildto(mid + 1 , r , rs[p]) ;
    add(p , ls[p] , 0) ; add(p , rs[p] , 0) ;
  }
  void buildback(int l , int r , int & p) { // 出边·线段树
    if(l == r) { p = l ; return ; }
    int mid = l + r >> 1 ; p = ++ cnt ;
    buildback(l , mid , ls[p]) ; buildback(mid + 1 , r , rs[p]) ;
    add(ls[p] , p , 0) ; add(rs[p] , p , 0) ;
  }
  void upd(int a , int b , int l , int r , int u , int p , int w) { // 入边
    if(a <= l && r <= b) { add(u , p , w) ; return ; }
    int mid = l + r >> 1 ;
    if(a <= mid) upd(a , b , l , mid , u , ls[p] , w) ;
    if(b > mid) upd(a , b , mid + 1 , r , u , rs[p] , w) ;
  }
  void upd2(int a , int b , int l , int r , int u , int p , int w) { // 出边
    if(a <= l && r <= b) { add(p , u , w) ; return ; }
    int mid = l + r >> 1 ;
    if(a <= mid) upd2(a , b , l , mid , u , ls[p] , w) ;
    if(b > mid) upd2(a , b , mid + 1 , r , u , rs[p] , w) ;
  }
  void main() {
    cin >> n >> m >> s ; cnt = n ; buildto(1 , n , rt1) ; buildback(1 , n , rt2) ;
    while(m --) {
      int opt ; cin >> opt ;
      if(opt == 1) { int v , u , w ; cin >> v >> u >> w ; add(v , u , w) ; }
      if(opt == 2) { int v , l , r , w ; cin >> v >> l >> r >> w ; upd(l , r , 1 , n , v , rt1 , w) ; }
      if(opt == 3) { int v , l , r , w ; cin >> v >> l >> r >> w ; upd2(l , r , 1 , n , v , rt2 , w) ; }
    }
    queue < int > q ; memset(dis , 0x3f , sizeof(dis)) ; dis[s] = 0 ; q.push(s) ;
    while(q.size()) {
      int u = q.front() ; q.pop() ; vis[u] = 0 ;
      for(int i = head[u] ; i ; i = e[i].nxt) {
        int v = e[i].v ;
        if(dis[v] > dis[u] + e[i].w) { dis[v] = dis[u] + e[i].w ; if(! vis[v]) { q.push(v) ; vis[v] = 1 ; } }
      }
    }
    for(int i = 1 ; i <= n ; i ++)
      if(dis[i] == dis[0]) { cout << -1 << ' ' ; }
      else { cout << dis[i] << ' ' ; }
  }
}
signed main() {
  _ios() ; ot() ;
  return stO_ATS_Orz :: main() , 0 ;
}
posted @ 2019-12-04 19:09  _Isaunoya  阅读(181)  评论(0编辑  收藏  举报