zoukankan      html  css  js  c++  java
  • BZOJ5017 [SNOI2017]炸弹

    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
    ", ans);
    170 }
    View Code
  • 相关阅读:
    vscode配置远程开发环境
    C++条件语句和循环语句
    C++整数相除、取模运算和自加
    C++基础数据类型
    C++定义常量、标识符命名、整型数据类型
    Android压力测试工具Monkey简介
    adb shell命令后出现error: device not found报错解决方案
    xadmin修改登录页面背景图
    windbg如何让.cmdtree自动执行?
    Rabbitmq入门到进阶看这篇就够了!
  • 原文地址:https://www.cnblogs.com/cychester/p/9831720.html
Copyright © 2011-2022 走看看