• 炸弹


    早就 A 了,偶然看到我的一个 219892 KiB 的代码,于是写下题解 .

    https://www.luogu.com.cn/problem/P5025,BZOJ 过了,luogu 没过

    题解:

    先线段树优化建图,跑 tarjan 缩点,跑的时候记录强连通分量能到达的左右端点,然后再 dfs 一遍,用 \(u\) 能到的所有节点 \(v\) 来更新它能到的左右端点 .

    然后就能求权值和了,答案显然能求了 .

    时间复杂度 \(O(n\log n)\) .

    丑陋の代码:

    #include<iostream>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<iterator>
    #include<cctype>
    #include<vector>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<cstdio>
    #include<bitset>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=5e5+500,M=2e6+500,MOD=1e9+7; // M = O(nlogn)
    // warning 这里 M 开的是线段树点数,所以除了 x,r 其他数组都要开 M 大小
    const ll INF_ll = 0x3f3f3f3f3f3f3f3f;
    const int INF_int = 0x3f3f3f3f;
    struct SimpleGraph
    {
        vector<int> g[M]; 
        inline void addedge(int u,int v){g[u].push_back(v);}
        inline void addedge2(int u,int v){addedge(u,v); addedge(v,u);}
        void print(int n) // debug
        {
            for (int i=1;i<=n;i++)
            {
                printf("%d: ", i);
                for (int v : g[i]) printf("%d, ", v);
                puts("");
            }
        }
        vector<int>& operator [] (const int& idx){return g[idx];}
        inline vector<int>& out_edges(int u){return g[u];}
    }g1,g2;
    // g1 初始连边
    // g2 缩完点
    
    int n;
    ll x[N], r[N];
    namespace Tools
    {
        template<typename ptr>
        inline void Unique(ptr begin,ptr end){sort(begin,end); unique(begin,end);}
        inline bool in_range(int L,int R,int l,int r){return (l<=L)&&(R<=r);} // [L, R] in [l, r]
        // Segment Tree Node: a
        struct Range{int l,r; Range(int L,int R){l=L; r=R;} Range() = default;}a[M];
    }
    using namespace Tools;
    namespace Tarjan
    {
        int dfn[M],low[M],belong[M],S[M],_left[M],_right[M],scc,tot,top;
        bool vis[M];
        void _dfs(int u)
        {
            dfn[u] = low[u] = ++tot; vis[u] = true;
            S[++top] = u;
            for (int v : g1[u])
            {
                if (!dfn[v]){_dfs(v); low[u] = min(low[u], low[v]);}
                else low[u] = min(low[u], dfn[v]);
            }
            if (dfn[u] == low[u])
            {
                int tmp; ++scc;
                do
                {
                    tmp = S[top];
                    belong[tmp] = scc;
                    vis[tmp] = false;
                    _left[scc]  = min(_left[scc] , a[tmp].l);
                    _right[scc] = max(_right[scc], a[tmp].r);
                    --top; 
                } while (u != tmp);
            }
        }
    }
    namespace Seg // Segment Tree
    {
        #define lc (u<<1)
        #define rc (u<<1|1)
        #define mid ((l+r)>>1)
        int ndcnt; // Node.
        int id[N]; // map: number -> node
        namespace __detail__
        {
            void connect(int u, int v, int L, int R, int l, int r)
            {
                if (in_range(l, r, L, R))
                {
                    if (u == v) return ; // self
                    g1.addedge(v,u); return ;
                }
                if (L <= mid) connect(lc, v, L, R, l, mid);
                if (R > mid)  connect(rc, v, L, R, mid+1, r);
            }
            void build(int u,int l,int r)
            {
                a[u] = Range(l, r); ndcnt = max(ndcnt, u);
                if (l == r)
                {
                    id[l] = u;
                    return ;
                }
                build(lc, l, mid); build(rc, mid+1, r);
                g1.addedge(u, lc); g1.addedge(u, rc);
            }
        }
        void connect(int v,int L,int R){__detail__::connect(1,v,L,R,1,n);}
        void build(){__detail__::build(1,1,n);}
        #undef lc
        #undef rc
        #undef mid
    }
    namespace ALL{using namespace Seg; using namespace Tarjan;}
    ll query(int x)
    {
        using namespace ALL;
        int u = belong[id[x]];
        return _right[u] - _left[u] + 1;
    }
    void dfs(int u)
    {
        using namespace ALL;
        vis[u] = true;
        for (int v : g2[u])
        {  
            if (!vis[v]) dfs(v);
            _left[u]  = min(_left[u] , _left[v]);
            _right[u] = max(_right[u], _right[v]);
        }
    }
    inline void _(){puts("APJ AK IOI!!");}
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("i.in","r",stdin);
    #endif
        using namespace ALL;
        memset(_left,INF_int,sizeof _left);
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%lld%lld",x+i,r+i);
        x[n+1] = INF_ll;
        build();
        for (int i=1;i<=n;i++)
        {
            if (!r[i]) continue;
            int L = lower_bound(x+1, x+1+n, x[i]-r[i]) - x,
                R = upper_bound(x+1, x+1+n, x[i]+r[i]) - x - 1;
            connect(id[i], L, R);
            a[id[i]]=Range(L, R);
        }
        _dfs(1);
        for (int u=1;u<=ndcnt;u++)
            for (int v : g1[u])
            {   
                int U=belong[u], V=belong[v];
                if (U!=V) g2.addedge(U, V);
            }
        for (int i=1;i<=scc;i++) Unique(g2[i].begin(), g2[i].end());
    	memset(vis,false,sizeof vis);
    	for(int i=1;i<=scc;i++)
    		if (!vis[i]) dfs(i);
        ll ans=0;
        for (int i=1;i<=n;i++) ans = (ans + query(i) * i) % MOD;
        printf("%lld\n", ans);
        return 0;
    }
    
  • 相关阅读:
    黑客书架上的书籍(转)
    vc 得到文件后缀名(转)
    配置IIS7(转)
    vs2008 目标框架 发布遇到的问题(转)
    CListCtrl用法(转)
    T400 折腾
    VS2008和.NET Framework3.5新功能(转)
    sql 2008 ctp 安装
    关于定位lsass内存中的明文密码(转)
    NT系统下木马进程的隐藏与检测(转)
  • 原文地址:https://www.cnblogs.com/CDOI-24374/p/15705995.html
Copyright © 2020-2023  润新知