[SNOI2017]炸弹[线段树优化建图]

[SNOI2017]炸弹

线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样…于是就可以发现有些是只有单向边的不能忘记更新,没了。

#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 = 5e5 + 10 ;
  const int mod = 1e9 + 7 ;
  int n , a[N] , r[N] , id[N] ;
  int minl[N << 2] , maxr[N << 2] , sccl[N << 2] , sccr[N << 2] , mx = 0 ;
  vii G[N << 2] ;
  void build(int l , int r , int p) {
    minl[p] = l ; maxr[p] = r ; cmax(mx , p) ;
    if(l == r) { id[l] = p ; return ; }
    int mid = l + r >> 1 ;
    build(l , mid , p << 1) ; build(mid + 1 , r , p << 1 | 1) ;
    G[p].push_back(p << 1) ; G[p].push_back(p << 1 | 1) ;
  }
  void upd(int a , int b , int l , int r , int p , int to) {
    if(a <= l && r <= b) { if(p ^ to) G[to].push_back(p) ; return ; }
    int mid = l + r >> 1 ;
    if(a <= mid) upd(a , b , l , mid , p << 1 , to) ;
    if(b > mid) upd(a , b , mid + 1 , r , p << 1 | 1 , to) ;
  }
  int low[N << 2] , dfn[N << 2] , idx = 0 ;
  int col[N << 2] , st[N << 2] , tp = 0 , num = 0 ;
  void tarjan(int u) {
    low[u] = dfn[u] = ++ idx ; st[++ tp] = u ;
    for(int v : G[u]) {
      if(! dfn[v]) { tarjan(v) ; cmin(low[u] , low[v]) ; }
      else if(! col[v]) { cmin(low[u] , dfn[v]) ; }
    }
    if(low[u] == dfn[u]) {
      ++ num ;
      do { col[st[tp]] = num ; cmin(sccl[num] , minl[st[tp]]) ; cmax(sccr[num] , maxr[st[tp]]) ; tp -- ; } while(st[tp + 1] ^ u) ;
    }
  }
  vii reG[N << 2] ;
  bool vis[N << 2] ;
  void dfs(int u) {
    vis[u] = 1 ;
    for(int v : reG[u]) {
      if(vis[v]) { cmin(sccl[u] , sccl[v]) ; cmax(sccr[u] , sccr[v]) ; }
      else { dfs(v) ; cmin(sccl[u] , sccl[v]) ; cmax(sccr[u] , sccr[v]) ; }
    }
  }
  void main() {
    cin >> n ; build(1 , n , 1) ;
    for(int i = 1 ; i <= n ; i ++) { cin >> a[i] >> r[i] ;  }
    a[n + 1] = 1e18 ; memset(sccl , 0x3f , sizeof(sccl)) ;
    for(int i = 1 ; i <= n ; i ++) {
      if(! r[i]) { continue ; }
      int bg = lower_bound(a + 1 , a + n + 1 , a[i] - r[i]) - a ;
      int ed = upper_bound(a + 1 , a + n + 1 , a[i] + r[i]) - a - 1 ;
      upd(bg , ed , 1 , n , 1 , id[i]) ; minl[id[i]] = bg ; maxr[id[i]] = ed ;
    }
    rep(i , 1 , mx) if(! dfn[i]) tarjan(i) ;
    rep(i , 1 , mx)
      for(int v : G[i])
        if(col[i] ^ col[v]) reG[col[i]].push_back(col[v]) ;
    memset(vis , 0 , sizeof(vis)) ;
    rep(i , 1 , num) if(! vis[i]) dfs(i) ;
    int ans = 0 ;
    rep(i , 1 , n) ans = (ans + i * (sccr[col[id[i]]] - sccl[col[id[i]]] + 1)) % mod ;
    cout << ans << '\n' ;
  }
}
signed main() {
  _ios() ; ot() ;
  return stO_ATS_Orz :: main() , 0 ;
}
posted @ 2019-12-04 21:11  _Isaunoya  阅读(255)  评论(0编辑  收藏  举报