zoukankan      html  css  js  c++  java
  • BZOJ 1791: [IOI2008]Island 岛屿

    传送门

    题解

    题意 = 找出无向基环树森林的每颗基环树的直径。 

    我们首先需要找到每颗基环树的环, 但是因为是无向图,用tarjan找环, 加个手工栈, 我也是看了dalao的博客才知道tarjan找无向图环 :

    dalao的链接

    然鹅大佬的方法有一点小问题, 无法找出只有两个节点的环,改动后代码:

     1 void dfs(int x, int last) {
     2     dfn[x] = ++sz;
     3     for(int i = head[x]; i; i = e[i].nxt) {
     4         if(i == last ^ 1) continue;
     5         int nt = e[i].to;
     6         if(dfn[nt]) {
     7             if(dfn[nt] < dfn[x]) continue;
     8             cur.push_back(x); mk[x] = 1;
     9             for(; nt != x; nt = pre[nt]) cur.push_back(nt), mk[nt] = 1;
    10         }
    11         else pre[nt] = x, dfs(nt, i);
    12     }
    13 }

    加了手工栈后的代码

     1 int lev2;
     2 
     3 int st_i2[N],st_x2[N],st_y2[N],st_t2[N];
     4 
     5 #define i st_i2[lev2]
     6 #define y st_y2[lev2]
     7 #define x st_x2[lev2]
     8 #define nt st_t2[lev2]
     9 
    10 void dfs(int u, int last) {
    11     lev2 = 1;
    12     st_x2[1] = u; st_y2[1] = last;
    13 start:;
    14     dfn[x] = ++sz;
    15     for(i = head[x]; i; i = e[i].nxt) {
    16         nt = e[i].to;
    17         if(i == ch(y)) continue;
    18         if(dfn[nt]) {
    19             if(dfn[nt] < dfn[x]) continue;
    20             cur.push_back(x); mk[x] = 1;
    21             for(; nt != x; nt = pre[nt]) mk[nt] = 1, cur.push_back(nt);
    22             continue;
    23         }
    24         pre[nt] = x;
    25         st_x2[lev2 + 1] = nt;
    26         st_y2[lev2 + 1] = i;
    27         lev2++;
    28         goto start;
    29 end:;
    30     }
    31     lev2--;
    32     if(lev2) goto end;
    33 }
    34 
    35 #undef i
    36 #undef y
    37 #undef x
    38 #undef nt

    设tmp 为某棵基环树的直径

    tmp可能是某个环上点的子树的直径, 也有可能是环上两个点之间的距离+两个点到子树的最大距离

    找出环后, 求出环上的每个点的子树中的直径, 每颗子树的直径中都更新 tmp的最大值。

    接着求出从环上每个点到它子树节点的最远距离$d$, tmp的最大值也可能为 $d_i + d_j + dist(i, j)$。

    这个式子最大值可以用拆环+单调队列O(N)求出。

    然后把tmp 加到最后答案

    代码

    为什么不加手工栈比加了手工栈慢20倍

      1 #include<cstring>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<vector>
      5 #define rd read()
      6 #define rep(i,a,b) for(int i = (a); i <= (b); ++i)
      7 #define per(i,a,b) for(int i = (a); i >= (b); --i)
      8 #define ll long long
      9 #define R register
     10 using namespace std;
     11 
     12 const int N = 1e6 + 1e5;
     13 
     14 int n, head[N], tot, dfn[N], pre[N], sz;
     15 int q[N], mk[N], pos[N];
     16 ll ans, d[N], f[N];
     17 
     18 vector<int> pt;
     19 vector<ll> len;
     20 
     21 struct edge {
     22     int nxt, to, val;
     23 }e[N << 2];
     24 
     25 int read() {
     26     R int X = 0, p = 1; R char c = getchar();
     27     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
     28     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
     29     return X * p;
     30 }
     31 
     32 void add(int u, int v, int val) {
     33     e[++tot].to = v;
     34     e[tot].val = val;
     35     e[tot].nxt = head[u];
     36     head[u] = tot;
     37 }
     38 
     39 int ch(int x) {
     40     return ((x + 1) ^ 1) - 1;
     41 }
     42 
     43 int lev2;
     44 
     45 int st_i2[N],st_x2[N],st_y2[N],st_t2[N];
     46 
     47 #define i st_i2[lev2]
     48 #define y st_y2[lev2]
     49 #define x st_x2[lev2]
     50 #define nt st_t2[lev2]
     51 
     52 void dfs(int u, int last) {
     53     lev2 = 1;
     54     st_x2[1] = u; st_y2[1] = last;
     55 start:;
     56     dfn[x] = ++sz;
     57     for(i = head[x]; i; i = e[i].nxt) {
     58         nt = e[i].to;
     59         if(i == ch(y)) continue;
     60         if(dfn[nt]) {
     61             if(dfn[nt] < dfn[x]) continue;
     62             pt.push_back(x); mk[x] = 1;
     63             for(; nt != x; nt = pre[nt]) mk[nt] = 1, pt.push_back(nt);
     64             continue;
     65         }
     66         pre[nt] = x;
     67         st_x2[lev2 + 1] = nt;
     68         st_y2[lev2 + 1] = i;
     69         lev2++;
     70         goto start;
     71 end:;
     72     }
     73     lev2--;
     74     if(lev2) goto end;
     75 }
     76 
     77 #undef i
     78 #undef y
     79 #undef x
     80 #undef nt
     81 
     82 int lev;
     83 int st_x[N], st_y[N], st_i[N], st_t[N];
     84 
     85 #define i st_i[lev]
     86 #define x st_x[lev]
     87 #define y st_y[lev]
     88 #define nt st_t[lev]
     89 
     90 void dfs2(int u, int fa) {
     91     lev = 1;
     92     st_x[1] = u; st_y[1] = fa;
     93 start:;
     94     for(i = head[x]; i; i = e[i].nxt) {
     95         nt = e[i].to;
     96         if(nt == y || mk[nt]) continue;
     97         st_x[lev + 1] = nt;
     98         st_y[lev + 1] = x;
     99         lev++;
    100         goto start;
    101 end:;
    102         f[x] = max(f[x], f[nt]);
    103         f[x] = max(f[x], d[x] + d[nt] + e[i].val);
    104         d[x] = max(d[x], d[nt] + e[i].val);
    105     }
    106     lev--;
    107     if(lev) goto end;
    108 }
    109 
    110 #undef i
    111 #undef x
    112 #undef y
    113 #undef nt
    114 
    115 void work(int x) {
    116     ll tmp = 0; int cnt;
    117     pt.clear(); len.clear();
    118     dfs(x, 0); cnt = pt.size();
    119     pt.push_back(pt[0]);
    120     len.push_back(0);
    121     for(R int i = 0; i < cnt; ++i) {
    122         for(R int k = head[pt[i]]; k; k = e[k].nxt) if(e[k].to == pt[(i + 1) % cnt])
    123             len.push_back(e[k].val);
    124     }
    125     for(R int i = 1; i < cnt; ++i)
    126         pt.push_back(pt[i]), len.push_back(len[i]);
    127 
    128     rep(i, 1, cnt * 2 - 1) {
    129         len[i] += len[i - 1];
    130     }
    131     rep(i, 0, cnt - 1) dfs2(pt[i], 0), tmp = max(tmp, f[pt[i]]);
    132     int l = 1, r = 0;
    133     rep(i, 0, cnt * 2 - 1) {
    134         while(l <= r && i - q[l] >= cnt) l++;
    135         if(l <= r) tmp = max(tmp, d[pt[i]] + d[pt[q[l]]] + len[i] - len[q[l]]);
    136         else tmp = max(tmp, d[pt[i]]);
    137         while(l <= r && d[pt[i]] - len[i] >= d[pt[q[r]]] - len[q[r]]) r--;
    138         q[++r] = i;
    139     }
    140     ans += tmp;
    141 }
    142 
    143 int main()
    144 {
    145     n = rd;
    146     rep(i, 1, n) {
    147         int v = rd, val = rd;
    148         add(i, v, val); add(v, i, val);
    149     }
    150     rep(i, 1, n) if(!dfn[i]) {
    151         work(i);
    152     }
    153     printf("%lld
    ", ans);
    154 }
    View Code
  • 相关阅读:
    Educational Codeforces Round 6
    Codeforces Round #373 (Div. 2)
    尺取法
    Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2)
    逆元(数论倒数)
    最大公约数gcd,最小公倍数lcm,扩展欧几里得
    hdu 6395 Sequence (分段矩阵快速幂)
    快速幂
    hdu 6432 Cyclic
    hdu 6397 charactor encoding
  • 原文地址:https://www.cnblogs.com/cychester/p/9559684.html
Copyright © 2011-2022 走看看