题目链接
这个题一开始一直很懵逼 不是很理解建图
手动模拟一下才发现这个建图的妙处
首先我们把所有的点都放到线段树的叶子上
当然线段树上的大区间肯定是要向小区间连边的
然后每个点对于它能炸到的
log
l
o
g
个区间进行连边
这样子一个强连通分量里的点一定是炸一个就能全炸的
缩完点我们考虑用拓扑排序来进行 dp d p
我们发现如果 v v 能被引爆,那么 u u 就能引爆能引爆的节点,所以我们要建反图进行拓扑排序 dp d p
然后做完了 复杂度 O(nlogn) O ( n l o g n ) 听说正解是 O(n) O ( n ) 的线性递推,不过反正把这个当板子打
Codes
#include<bits/stdc++.h>
#define int long long
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)
#define pb push_back
using namespace std;
int read() {
int _ = 0, ___ = 1; char __ = getchar();
for(; !isdigit(__); __ = getchar()) if(__ == '-') ___ = -1;
for(; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
return _ * ___;
}
const int N = 5e5 + 10, mod = 1e9 + 7;
int n, x[N], r[N], pos[N];
vector<int> G1[N << 2], G2[N << 2], kuai[N << 2];
int color, Mx[N << 2], Mn[N << 2], be[N << 2];
int mn[N << 2], mx[N << 2], de[N << 2];
int fl[N << 2], fr[N << 2], num;
void build(int bh, int l, int r) {
//cout << bh << ' ' << l << ' ' << r << endl;
num = max(num, bh);
mx[bh] = r, mn[bh] = l;
if(l == r)
pos[l] = bh;
else {
build(ls, l, mid), build(rs, mid + 1, r);
G1[bh].pb(ls), G1[bh].pb(rs);
}
}
void update(int bh, int l, int r, int p, int x, int y) {
if(x <= l && r <= y)
G1[p].pb(bh);
else {
if(x <= mid) update(ls, l, mid, p, x, y);
if(y > mid) update(rs, mid + 1, r, p, x, y);
}
}
namespace Tarjan {
int low[N << 2], Sta[N << 2], dfn[N << 2], cnt, top, ins[N << 2];
void dfs(int x) {
low[x] = dfn[x] = ++ cnt; Sta[++ top] = x; ins[x] = true;
for(auto v : G1[x]) {
if(!dfn[v]) {
dfs(v);
low[x] = min(low[x], low[v]);
}
else if(ins[v])
low[x] = min(low[x], dfn[v]);
}
if(low[x] == dfn[x]) {
++ color; Mx[color] = INT_MIN, Mn[color] = INT_MAX;
do {
ins[Sta[top]] = false;
be[Sta[top]] = color;
kuai[color].pb(Sta[top]);
Mx[color] = max(Mx[color], mx[Sta[top]]);
Mn[color] = min(Mn[color], mn[Sta[top]]);
}while(Sta[top --] != x);
//cout << color << ' ' << Mn[color] << ' ' << Mx[color] << endl;
}
}
void New_Graph() {
map<int, int> G[N << 2];
for(int i = 1; i <= color; ++ i)
for(auto u : kuai[i])
for(auto v : G1[u]) {
if(be[u] != be[v] && !G[be[u]][be[v]]) {
G2[be[v]].pb(be[u]);
G[be[v]][be[u]] = 1;
++ de[be[u]];
}
// printf("%lld %lld %lld %lld %lld %lld\n", u, v, mn[u], mx[u], mn[v], mx[v]);
}
}
}
void Topsort() {
queue<int> q;
for(int i = 1; i <= color; ++ i) {
fl[i] = Mn[i], fr[i] = Mx[i];
if(!de[i]) q.push(i);
}
while(!q.empty()) {
int k = q.front(); q.pop();
for(auto v : G2[k]) {
if(!(-- de[v]))
q.push(v);
fr[v] = max(fr[k], fr[v]);
fl[v] = min(fl[k], fl[v]);
}
}
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("2255.in", "r", stdin);
freopen("2255.out", "w", stdout);
#endif
int L, R, ans = 0; n = read();
for(int i = 1; i <= n; ++ i)
x[i] = read(), r[i] = read();
build(1, 1, n);
for(int i = 1; i <= n; ++ i) {
L = lower_bound(x + 1, x + n + 1, x[i] - r[i]) - x;
R = upper_bound(x + 1, x + n + 1, x[i] + r[i]) - x;
//cout << i << ' ' << L << ' ' << R - 1 << endl;
if(R - L <= 1) continue;
update(1, 1, n, pos[i], L, R - 1);
}
for(int i = 1; i <= num; ++ i)
if(!Tarjan::dfn[i])
Tarjan::dfs(i);
Tarjan::New_Graph();
Topsort();
for(int i = 1; i <= n; ++ i) {
(ans += (fr[be[pos[i]]] - fl[be[pos[i]]] + 1) * i % mod) %= mod;
//cout << ' ' << i << ' ' << fr[be[pos[i]]] << ' ' << fl[be[pos[i]]] << endl;
}
printf("%lld\n", ans);
return 0;
}