cychester

BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

Solution

一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门

然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$

然后拓扑排序。 由于一次引爆的炸弹 一定是一个连续的区间内, 所以只需要记录左右边界, 并将左右边界转移给能到达它的联通块。

没写手工栈一直RE的我心里$mmp$啊。 为什么网上的题解都不写手工栈$QAQ$

Code

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define rd read()
  5 #define ll long long
  6 using namespace std;
  7   
  8 const int N = 2000010;
  9 const int mod = 1e9 + 7;
 10 const ll inf = 3e18;
 11   
 12 int n, lscnt;
 13 int head[N], tot;
 14 int Head[N], Tot;
 15 int low[N], dfn[N], dfstot;
 16 int c[N], col;
 17 ll minn[N], maxn[N], ls[N];
 18 int st[N], tp;
 19 bool vis[N], inq[N];
 20   
 21 struct edge {
 22     int nxt, to;
 23 }e[N * 10], E[N * 10];
 24   
 25 struct boom {
 26     ll pos, r;
 27 }bo[N];
 28   
 29 ll read() {
 30     ll X = 0, p = 1; char c = getchar();
 31     for (; c > '9' || c < '0'; c = getchar())
 32         if (c == '-') p = -1;
 33     for (; c >= '0' && c <= '9'; c = getchar())
 34         X = X * 10 + c - '0';
 35     return X * p;
 36 }
 37   
 38 void add(int u, int v) {
 39     e[++tot].to = v;
 40     e[tot].nxt = head[u];
 41     head[u] = tot;
 42 }
 43   
 44 void Add(int u, int v) {
 45     E[++Tot].to = v;
 46     E[Tot].nxt = Head[u];
 47     Head[u] = Tot;
 48 }
 49   
 50 namespace SegT {
 51 #define mid ((l + r) >> 1)
 52     int lc[N], rc[N], root, cnt;
 53   
 54     void build(int &p, int l, int r) {
 55         if (l == r) {
 56             p = l; return;
 57         }
 58         p = ++cnt;
 59         build(lc[p], l, mid);
 60         build(rc[p], mid + 1, r);
 61         add(p, lc[p]); add(p, rc[p]);
 62     }
 63   
 64     void update(int L, int R, int c, int l, int r, int x) {
 65         if (L > R) return;
 66         if (L <= l && r <= R) {
 67             add(c, x); return;
 68         }
 69         if (mid >= L)
 70             update(L, R, c, l,mid, lc[x]);
 71         if (mid < R)
 72             update(L, R, c, mid + 1, r, rc[x]);
 73     }
 74 }using namespace SegT;
 75   
 76 #define R register
 77 int stx[N], sti[N], lv, stnt[N];
 78 #define u stx[lv]
 79 #define nt stnt[lv]
 80 #define i sti[lv]
 81 void tarjan(int x) {
 82     lv = 1; stx[1] = x;
 83 start:;
 84     low[u] = dfn[u] = ++dfstot;
 85     inq[u] = true; st[++tp] = u;
 86     for (i = head[u]; i; i = e[i].nxt) {
 87         nt = e[i].to;
 88         if (!dfn[nt]) {
 89 //         tarjan(nt);
 90             stx[lv + 1] = nt;
 91             lv++;
 92             goto start;
 93             end:;
 94             low[u] = min(low[u], low[nt]);
 95         }
 96         else if (inq[nt]) low[u] = min(low[u], dfn[nt]);
 97     }
 98     if (low[u] == dfn[u]) {
 99         col++;
100         for (; tp;) {
101             int z = st[tp--];
102             inq[z] = false;
103             if (z <= n) 
104                 maxn[col] = max(maxn[col], bo[z].pos + bo[z].r),
105                 minn[col] = min(minn[col], bo[z].pos - bo[z].r);
106             c[z] = col;
107             if (z == u) break;
108         }
109     }
110     --lv;
111 if (lv) goto end;
112 }
113 #undef u
114 #undef nt
115 #undef i
116   
117 void dfs(int u) {
118     vis[u] = true;
119     for (R int i = Head[u]; i; i = E[i].nxt) {
120         int nt = E[i].to;
121         if (vis[nt] == false) dfs(nt);
122         minn[u] = min(minn[u], minn[nt]);
123         maxn[u] = max(maxn[u], maxn[nt]);
124     }
125 }
126   
127 int fdl(ll x) {
128     return lower_bound(ls + 1, ls + 1 + lscnt, x) - ls;
129 }
130   
131 int fdr(ll x) {
132     int re = lower_bound(ls + 1, ls + 1 + lscnt, x) - ls;
133     if (ls[re] == x) return re;
134     else return re - 1;
135 }
136   
137 int main()
138 {
139     cnt = n = rd;
140     for (R int i = 1; i <= n; ++i) {
141         bo[i].pos = rd; bo[i].r = rd;
142         ls[++lscnt] = bo[i].pos;
143     }
144     sort(ls + 1, ls + 1 + lscnt);
145     lscnt = unique(ls + 1, ls + 1 + lscnt) - ls - 1;
146     build(root, 1, n);
147     for (int i = 1; i <= n; ++i) {
148         int l = fdl(bo[i].pos - bo[i].r), r = fdr(bo[i].pos + bo[i].r), m = fdl(bo[i].pos);
149         update(l, m - 1, m, 1, n, root);
150         update(m + 1, r, m, 1, n, root);
151     }
152     for (int i = 1; i < N; ++i)
153         maxn[i] = -inf, minn[i] = inf;
154     for (int i = 1; i <= cnt; ++i)
155         if (!dfn[i]) tarjan(i);
156     for (int u = 1; u <= cnt; ++u) 
157         for (int i = head[u]; i; i = e[i].nxt) {
158             int v = e[i].to;
159             if (c[u] == c[v])
160                 continue;
161             Add(c[u], c[v]);
162         }
163     for (int i = 1; i <= col; ++i) dfs(i);
164     ll ans = 0;
165     for (int i = 1; i <= n; ++i) {
166         int l = fdl(minn[c[i]]), r = fdr(maxn[c[i]]);
167         (ans += 1LL * i * (r - l + 1) % mod) %= mod;
168     }
169     printf("%lld\n", ans);
170 }
View Code

 

posted on 2018-10-22 18:17  cychester  阅读(280)  评论(0编辑  收藏  举报

导航