[SNOI 2017] 炸弹 loj2255 线段树优化建图 Tarjan求强联通分量

版权声明:_ https://blog.csdn.net/lunch__/article/details/81841896

题目链接
这个题一开始一直很懵逼 不是很理解建图
手动模拟一下才发现这个建图的妙处

首先我们把所有的点都放到线段树的叶子上
当然线段树上的大区间肯定是要向小区间连边的
然后每个点对于它能炸到的 l o g 个区间进行连边

这样子一个强连通分量里的点一定是炸一个就能全炸的

缩完点我们考虑用拓扑排序来进行 d p

我们发现如果 v 能被 u 引爆,那么 u 就能引爆 v 能引爆的节点,所以我们要建反图进行拓扑排序 d p

然后做完了 复杂度 O ( n l o g 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;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81841896