• POI2015 解题报告


    由于博主没有BZOJ权限号, 是在洛咕做的题~

    完成了13题(虽然有一半难题都是看题解的QAQ)剩下的题咕咕咕~~

     

    Luogu3585 [POI2015]PIE

    Solution

    模拟, 按顺序搜索, 把搜索到的需要印却没有印的点 和 印章的第一个点重合, 并印上。

    另外, 纸上需要印的点 和 印章上沾墨水的点用数组储存, 能加快很多

    Code

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<vector>
     5 #define R register
     6 using namespace std;
     7 typedef pair<int, int> P;
     8 
     9 const int N = 1e3 + 5;
    10 
    11 int n, m, a, b;
    12 int stx, sty;
    13 char s[N], in[N][N], mp[N][N];
    14 
    15 vector<P> need, offer;
    16 
    17 int jud(int x, int y) {
    18     if (x <= 0 || y <= 0 || x > n || y > m)
    19         return 0;
    20     return 1;
    21 }
    22 
    23 #define X first
    24 #define Y second
    25 int col(int x, int y) {
    26     for (R int i = 0, up = offer.size(); i < up; ++i) {
    27         int onx = x + offer[i].X - stx, ony = y + offer[i].Y - sty;
    28         if (!jud(onx, ony)) return 0;
    29         if (mp[onx][ony] == '.') return 0;
    30         mp[onx][ony] = '.';
    31     }
    32     return 1;
    33 }
    34 
    35 int work() {
    36     stx = sty = 0;
    37     offer.clear(); need.clear();
    38     for (R int i = 1; i <= n; ++i) scanf("%s", mp[i] + 1);
    39     for (R int i = 1; i <= a; ++i) scanf("%s", in[i] + 1);
    40     for (R int i = 1; i <= n; ++i)
    41         for (R int j = 1; j <= m; ++j) if (mp[i][j] == 'x')
    42             need.push_back(P(i, j));
    43     for (R int i = 1; i <= a; ++i)
    44         for (R int j = 1; j <= b; ++j) if (in[i][j] == 'x') {
    45             offer.push_back(P(i, j));
    46             if (!stx) stx = i, sty = j;
    47         }
    48     
    49     for (int i = 0, up = need.size(); i < up; ++i)
    50         if (mp[need[i].X][need[i].Y] == 'x')
    51             if (!col(need[i].X, need[i].Y)) return 0;
    52     return 1;
    53 }
    54 #undef X
    55 #undef Y
    56 
    57 int main()
    58 {
    59     int Q; scanf("%d", &Q);
    60     for (; Q; Q--) {
    61         scanf("%d%d%d%d", &n, &m, &a, &b);
    62         if (work()) puts("TAK");
    63         else puts("NIE");
    64     }
    65 }
    Luogu3585 PIE

    Luogu3594[POI2015]WIL-Wilcze doły

    Solution

    单调队列, 将长度为 $d$ 的最大字段和加入队列, 并且队列内 字段和 单调递减

    开个双指针 $i, j$ 表示要选择的最长的连续区间的两端。

    随着 $i$ 增加,把新的 长度为$d$ 的子段和加入队列。

    然后逐渐右移指针$j$, 直到找到第一个$<=p$的区间。 随着$j$增加, 把 队列内超出范围的子段和 弹出

    Code

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rd read()
     5 #define ll long long
     6 #define R register
     7 using namespace std;
     8 
     9 const int N = 2e6 + 5;
    10 
    11 int n, p, d;
    12 ll sum[N], a[N];
    13 ll q[N];
    14 
    15 ll read() {
    16     ll X = 0, p = 1; char c = getchar();
    17     for (; c > '9' || c < '0'; c = getchar())
    18         if (c == '-') p = -1;
    19     for (; c >= '0' && c <= '9'; c = getchar())
    20         X = X * 10 + c - '0';
    21     return X * p;
    22 }
    23 
    24 int main()
    25 {
    26     n = rd; p = rd; d = rd;
    27     for (R int i = 1; i <= n; ++i)
    28         a[i] = rd, sum[i] = sum[i - 1] + a[i];
    29     int l = 1, r = 0, ans = d;
    30     for (int i = d, j = 0; i <= n; ++i) {
    31         ll tmp = sum[i] - sum[i - d];
    32         while (l <= r && sum[q[r]] - sum[q[r] - d] <= tmp) r--;
    33         q[++r] = i;
    34         tmp = sum[q[l]] - sum[q[l] - d];
    35         while (sum[i] - sum[j] - tmp > p) {
    36             j++;
    37             while (l <= r && q[l] - d < j) l++;
    38             tmp = sum[q[l]] - sum[q[l] - d];
    39         }
    40         ans = max(ans, i - j);
    41     }
    42     printf("%d
    ", ans);
    43 }
    Luogu3594 WIL-Wilcze doły

    Luogu3586[POI2015]LOG

    Solution

    树状数组

    先考虑怎样判断是否符合条件, 数列中 $>=s$的个数为$cnt$, 若剩余的$<s$的数的和 $>= (c-cnt)*s$ 即可满足条件

    这样我们就需要知道数列中有多少个数$>=s$, 以及$<s$的数的和, 可以用两个树状数组维护.

    最后一个点 开LL

    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 = 2e6 + 5;
     9 
    10 ll a[N], n, m, tot;
    11 ll cnt[N], ls[N], sum[N];
    12 
    13 struct node {
    14     int typ, x;
    15     ll y;
    16 }pro[N];
    17 
    18 ll read() {
    19     ll X = 0, p = 1; char c = getchar();
    20     for (; c > '9' || c < '0'; c = getchar())
    21         if (c == '-') p = -1;
    22     for (; c >= '0' && c <= '9'; c = getchar())
    23         X = X * 10 + c - '0';
    24     return X * p;
    25 }
    26 
    27 int lowbit(int x) {
    28     return x & -x;
    29 }
    30 
    31 template <typename T>
    32 void add(int x, ll d, T *s) {
    33     for (; x <= tot; x += lowbit(x))
    34         s[x] += d;
    35 }
    36 
    37 template <typename T>
    38 T query(int x, T *s) {
    39     T re = 0;
    40     for (; x; x -= lowbit(x))
    41         re += s[x];
    42     return re;
    43 }
    44 
    45 int fd(ll x) {
    46     return lower_bound(ls + 1, ls + 1 + tot, x) - ls;
    47 }
    48 
    49 int main()
    50 {
    51     n = rd; m = rd;
    52     tot = 1;
    53     for (int i = 1; i <= m; ++i) {
    54         char ch = getchar();
    55         while (ch > 'Z' || ch < 'A') ch = getchar();
    56         if (ch == 'U') {
    57             pro[i].typ = 1; pro[i].x = rd; pro[i].y = rd;
    58             ls[++tot] = pro[i].y;
    59         }
    60         else {
    61             pro[i].typ = 2; pro[i].x = rd; pro[i].y = rd;
    62         }
    63     }
    64     sort(ls + 1, ls + 1 + tot);
    65     tot = unique(ls + 1, ls + 1 + tot) - ls - 1;
    66     for (int i = 1; i <= n; ++i)
    67         add(1, 1, cnt);
    68     for (int i = 1; i <= m; ++i) {
    69         if (pro[i].typ == 1) {
    70             int ch = fd(a[pro[i].x]);
    71             add(ch, -1, cnt);
    72             add(ch, -ls[ch], sum);
    73             ch = fd(pro[i].y);
    74             add(ch, 1, cnt);
    75             add(ch, ls[ch], sum);
    76             a[pro[i].x] = pro[i].y;
    77         }
    78         else {
    79             int ch = fd(pro[i].y), num;
    80             num = n - query(ch - 1, cnt);
    81             ll tmp = (pro[i].x - num) * pro[i].y;
    82             if (query(ch - 1, sum) >= tmp)
    83                 puts("TAK");
    84             else puts("NIE");
    85         }
    86     }
    87 }
    Luogu3586 LOG

    Luogu3584[POI2015]LAS

    Solution

    环形DP

    $S$ 表示第$i$个人 以及和他相邻的两个人吃哪边的食物, 例如$S$的二进制上有4, 就表示第$i-1$个人 吃右边的食物, 反之, 则吃左边的食物

    设置状态$f[i][S]$ 表示第$i$ 个人, 他相邻的吃食物的情况 为$S$, 能否符合要求。 

    由于环形最后一个人会影响第一个人, 则先枚举 第一个人, 到最后一个人判断是否存在与第一个人状态相符的情况 符合要求。

    Code

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rd read()
     5 #define db double
     6 using namespace std;
     7 
     8 const int N = 1e6 + 5;
     9 
    10 int n, c[N], f[N][8], ans[N], path[N][8];
    11 
    12 int read() {
    13     int X = 0, p = 1; char c = getchar();
    14     for (; c > '9' || c < '0'; c = getchar())
    15         if (c == '-') p = -1;
    16     for (; c >= '0' && c <= '9'; c = getchar())
    17         X = X * 10 + c - '0';
    18     return X * p;
    19 }
    20 
    21 int ch(int x) {
    22     return (x + n) % n;
    23 }
    24 
    25 int jud(int x, int S) {
    26     int le, re, me;
    27     le = (S >> 2) & 1; re = S & 1; me = (S >> 1) & 1;
    28     db now = c[ch(x + me)], nxt;
    29     if (!me && le) now /= 2;
    30     if (me && !re) now /= 2;
    31     nxt = c[ch(x + (!me))];
    32     if (me && le) nxt /= 2;
    33     if (!me && !re) nxt /= 2;
    34     if (nxt > now) return 0;
    35     else return 1;
    36 }
    37 
    38 
    39 int work(int S) {
    40     memset(f, 0, sizeof (f));
    41     f[0][S] = 1;
    42     for (int i = 1; i < n; ++i) 
    43         for (int now = 0; now < 8; ++now) if (jud(i, now)) 
    44             for (int pre = 0; pre <= 4; pre += 4) if (f[i - 1][pre + (now >> 1)])
    45                 f[i][now] = 1, path[i][now] = pre + (now >> 1);
    46     if (!f[n - 1][S >> 1] && !f[n - 1][(S >> 1) + 4])
    47         return 0;
    48     if (f[n - 1][S >> 1]) {
    49         for (int now = S >> 1, i = n - 1; ~i; now = path[i][now], --i)
    50             ans[i] = (now & 2) >> 1;
    51         for (int i = 0; i < n; ++i)
    52             printf("%d ", (ans[i] + i) % n + 1);
    53     }
    54     else {
    55         for (int now = (S >> 1) + 4, i = n - 1; ~i; now = path[i][now], --i)
    56             ans[i] = (now & 2) >> 1;
    57         for (int i = 0; i < n; ++i)
    58             printf("%d ", (ans[i] + i) % n + 1);
    59     }
    60     return 1;
    61 }
    62 
    63 int main()
    64 {
    65     n = rd;
    66     for (int i = 0; i < n; ++i)
    67         c[i] = rd;
    68     for (int i = 0; i < 8; ++i) if(jud(0, i))
    69         if (work(i)) return 0;
    70     puts("NIE");
    71 }
    Luogu3584 LAS

    Luogu3588[POI2015]PUS

    Solution

    线段树优化建树+差分约束

    我们最初的想法应该是 在区间$[L,R]$内 选中的数向 未被选中的数连一条长度为$1$的边, 一次操作便有$N^2$条边, 这样肯定会MLE+TLE

    于是我们又想到另外建一个虚点, 被选中的数向虚点建一条长度为$1$ 的边, 虚点再向未被选中的数 连长度为0的边, 这样一次操作便有$N$条边, 仍会MLE+TLE

    于是我们用线段树优化建图, 所有操作中 区间约有$k+1$段, 所以虚点向区间连边, 被选中的点再向虚点连边。 就解决了这个问题。

    最后再差分约束一下。

    Code

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<queue>
      5 #define rd read()
      6 using namespace std;
      7 
      8 const int N = 4e5 + 5;
      9 
     10 int head[N], tot;
     11 int n, dis[N], m, p, vis[N], r[N];
     12 int pre[N];
     13 
     14 struct edge {
     15     int nxt, to, w;
     16 }e[N << 2];
     17 
     18 queue<int> q;
     19 
     20 int read() {
     21     int X = 0, p = 1; char c = getchar();
     22     for (; c > '9' || c < '0'; c = getchar())
     23         if (c == '-') p = -1;
     24     for (; c >= '0' && c <= '9'; c = getchar())
     25         X = X * 10 + c - '0';
     26     return X * p;
     27 }
     28 
     29 void add(int u, int v, int w) {
     30     e[++tot].to = v;
     31     e[tot].nxt = head[u];
     32     e[tot].w = w;
     33     r[v]++;
     34     head[u] = tot;
     35 }
     36 
     37 namespace SegT {
     38     int lc[N], rc[N], cnt, root;
     39 #define mid ((l + r) >> 1)
     40     
     41     void build(int &x, int l, int r) {
     42         if (l == r) {
     43             x = l; return;
     44         }
     45         x = ++cnt;
     46         build(lc[x], l, mid);
     47         build(rc[x], mid + 1, r);
     48         add(lc[x], x, 0);
     49         add(rc[x], x, 0);
     50     }
     51 
     52     void update(int L, int R, int c, int l, int r, int x) {
     53         if (L > R) return;
     54         if (L <= l && r <= R) {
     55             add(x, c, 0); return;
     56         }
     57         if (mid >= L)
     58             update(L, R, c, l, mid, lc[x]);
     59         if (mid < R)
     60             update(L, R, c, mid + 1, r, rc[x]);
     61     }
     62 }using namespace SegT;
     63 
     64 void cmax(int &A, int B) {
     65     if (A < B)
     66         A = B;
     67 }
     68 
     69 void Topsort() {
     70     for (int i = 1; i <= cnt; ++i) {
     71         if (!dis[i]) dis[i] = 1;
     72         if (!r[i]) q.push(i);
     73     }
     74     for (int u; !q.empty();) {
     75         u = q.front(); q.pop();
     76         vis[u] = 1;
     77         for (int i = head[u]; i; i = e[i].nxt) {
     78             int nt = e[i].to;
     79             cmax(dis[nt], dis[u] + e[i].w);
     80             if (!(--r[nt])) q.push(nt);
     81         }
     82     }
     83 }
     84 
     85 int main()
     86 {
     87     cnt = n = rd; p = rd; m = rd;
     88     for (int i = 1; i <= p; ++i) {
     89         int pos = rd, x = rd;
     90         pre[pos] = dis[pos] = x;
     91     }
     92     build(root, 1, n);
     93     for (; m; m--) {
     94         int l = rd, r = rd, num = rd;
     95         int last = l, now;
     96         ++cnt;
     97         for (; num; --num) {
     98             add(cnt, now = rd, 1);
     99             update(last, now - 1, cnt, 1, n, root);
    100             last = now + 1;
    101         }
    102         update(now + 1, r, cnt, 1, n, root);
    103     }
    104     Topsort();
    105     for (int i = 1; i <= n; ++i) 
    106         if (!vis[i] || dis[i] > 1e9 || (dis[i] > pre[i] && pre[i]))
    107             return puts("NIE"), 0;
    108     puts("TAK");
    109     for (int i = 1; i <= n; ++i)
    110         printf("%d ", dis[i]);
    111 }
    Luogu3588 PUS

    Luogu3596[POI2015]MOD

    Solution

    树形DP

    确实有难度啊QAQ

    要求出每个子树的直径, 以及删去子树后剩下的那棵树的直径。

    要使合并后的树直径最小, 需要把两棵树的直径的中点连起来, 设两个直径分别为 $f, g$最后得到的直径为 $max{f, g, (f+1)/2+(g+1)/2+1}$

    要使合并后的树直径最大, 则把直径两端给连起来, 为$f+g+1$

    状态转移不好讲, 就讲变量的意义, 具体看代码里的两个$dp$

    $f[i]$ 表示 以$i$为根的子树的直径

    $w[i][0]$ 表示以 $i$的子节点 为根的子树的直径中  最大的直径

    $w[i][1]$ 表示以 $i$的子节点 为根的子树的直径中 第二大的直径

    $d[i][0]$ 表示从 $i$ 出发 往下 的最长链的长度

    $d[i][1]$  和 $d[i][2]$ 依次类推

    $line[i]$ 表示 从$i$开始, 到 除$i$外的子节点 所能得到的最长链

    $g[i]$ 表示删去 以$i$ 为节点的子树后 得到的树 的直径

    最后要得到方案 :

    直径最长则 $bfs$ 求出两条直径的端点

    直径最短, 则先求出两条直径的端点, 然后往上跳, 找到直径的中点

    总复杂度$O(N)$

    Code

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<queue>
      5 #define rd read()
      6 const int N = 5e5 + 5;
      7 using namespace std;
      8 
      9 int f[N], g[N], d[N][3], w[N][2], line[N], n, fa[N];
     10 int head[N], tot;
     11 int ansmax, ansmin = N, maxx, maxy, minx, miny;
     12 int diax1, diay1, diax2, diay2;
     13 int dep[N], vis[N];
     14 
     15 queue<int> q;
     16 
     17 struct edge {
     18     int nxt, to;
     19 }e[N << 1];
     20 
     21 int read() {
     22     int X = 0, p = 1; char c = getchar();
     23     for (; c > '9' || c < '0'; c = getchar())
     24         if (c == '-') p = -1;
     25     for (; c >= '0' && c <= '9'; c = getchar())
     26         X = X * 10 + c - '0';
     27     return X * p;
     28 }
     29 
     30 void add(int u, int v) {
     31     e[++tot].to = v;
     32     e[tot].nxt = head[u];
     33     head[u] = tot;
     34 }
     35 
     36 void cmax(int &A, int B) {
     37     if (A < B)
     38         A = B;
     39 }
     40 
     41 void cmin(int &A, int B) {
     42     if (A > B)
     43         A = B;
     44 }
     45 
     46 void dp1(int u) {
     47     for (int i = head[u]; i; i = e[i].nxt) {
     48         int nt = e[i].to;
     49         if (nt == fa[u]) continue;
     50         dep[nt] = dep[u] + 1;
     51         fa[nt] = u;
     52         dp1(nt);
     53         cmax(f[u], f[nt]);
     54         int tmp = d[nt][0] + 1;
     55         if (tmp > d[u][0])
     56             d[u][2] = d[u][1], d[u][1] = d[u][0], d[u][0] = tmp;
     57         else if (tmp > d[u][1])
     58             d[u][2] = d[u][1], d[u][1] = tmp;
     59         else if (tmp > d[u][2])
     60             d[u][2] = tmp;
     61         tmp = f[nt];
     62         if (tmp > w[u][0])
     63             w[u][1] = w[u][0], w[u][0] = tmp;
     64         else if (tmp > w[u][1])
     65             w[u][1] = tmp;
     66     }
     67     cmax(f[u], d[u][0] + d[u][1]);
     68 }
     69 
     70 void dp2(int u) {
     71     if (u != 1) {
     72         if (ansmax < g[u] + f[u] + 1) {
     73             ansmax = g[u] + f[u] + 1;
     74             maxx = fa[u]; maxy = u;
     75         }
     76         int res = max(g[u], f[u]);
     77         cmax(res, (g[u] + 1) / 2 + (f[u] + 1) / 2 + 1);
     78         if (ansmin > res) {
     79             ansmin = res;
     80             minx = fa[u]; miny = u;
     81         }
     82     }
     83     for (int i = head[u]; i; i = e[i].nxt) {
     84         int nt = e[i].to;
     85         if (nt == fa[u]) continue;
     86         cmax(line[nt], line[u] + 1);
     87         cmax(g[nt], g[u]);
     88         int tmp = d[nt][0] + 1;
     89         if (tmp == d[u][0]) {
     90             cmax(g[nt], d[u][1] + d[u][2]);
     91             cmax(g[nt], line[u] + d[u][1]);
     92             cmax(line[nt], d[u][1] + 1);
     93         }
     94         else if (tmp == d[u][1]) {
     95             cmax(g[nt], d[u][0] + d[u][2]);
     96             cmax(g[nt], line[u] + d[u][0]);
     97             cmax(line[nt], d[u][0] + 1);
     98         }
     99         else {
    100             cmax(g[nt], d[u][0] + d[u][1]);
    101             cmax(g[nt], line[u] + d[u][0]);
    102             cmax(line[nt], d[u][0] + 1);
    103         }
    104         tmp = f[nt];
    105         if (tmp == w[u][0]) 
    106             cmax(g[nt], w[u][1]);
    107         else cmax(g[nt], w[u][0]);
    108         dp2(nt);
    109     }
    110 }
    111 
    112 void outputmax() {
    113     memset(vis, 0, sizeof(vis));
    114     printf("%d %d %d", ansmax, maxx, maxy);
    115     q.push(maxx);
    116     vis[maxx] = 1;
    117     for (int u; !q.empty();) {
    118         u = q.front(); q.pop();
    119         maxx = u;
    120         for (int i = head[u]; i; i = e[i].nxt) {
    121             int nt = e[i].to;
    122             if (nt == maxx || nt == maxy) continue;
    123             if (vis[nt]) continue;
    124             q.push(nt);
    125             vis[nt] = 1;
    126         }
    127     }
    128     q.push(maxy);
    129     vis[maxy] = 1;
    130     for (int u; !q.empty();) {
    131         u = q.front(); q.pop();
    132         maxy = u;
    133         for (int i = head[u]; i; i = e[i].nxt) {
    134             int nt = e[i].to;
    135             if (vis[nt]) continue;
    136             q.push(nt);
    137             vis[nt] = 1;
    138         }
    139     }
    140     printf(" %d %d
    ", maxx, maxy);
    141 }
    142 
    143 int bfs(int S) {
    144     memset(vis, 0, sizeof(vis));
    145     q.push(S);
    146     vis[S] = 1;
    147     int re;
    148     for (int u; !q.empty();) {
    149         u = q.front(); q.pop();
    150         re = u;
    151         for (int i = head[u]; i; i = e[i].nxt) {
    152             int nt = e[i].to;
    153             if ((u == minx && nt == miny) || (u == miny && nt == minx))
    154                 continue;
    155             if (vis[nt]) continue;
    156             q.push(nt);
    157             vis[nt] = 1;
    158         }
    159     }
    160     return re;
    161 }
    162 
    163 int solve(int x, int y, int len) {
    164     int rest = len;
    165     if (dep[x] < dep[y]) swap(x, y);
    166     while (rest != (len + 1) / 2)
    167         x = fa[x], rest --;
    168     return x;
    169 }
    170 
    171 int main()
    172 {
    173     n = rd; 
    174     for (int i = 1; i < n; ++i) {
    175         int u = rd, v = rd;
    176         add(u, v); add(v, u);
    177     }
    178     dp1(1); dp2(1);
    179     printf("%d %d %d", ansmin, minx, miny);
    180     diax1 = bfs(minx); diay1 = bfs(diax1);
    181     diax2 = bfs(miny); diay2 = bfs(diax2);
    182     printf(" %d %d
    ", solve(diax1, diay1, g[miny]), solve(diax2, diay2, f[miny]));
    183     outputmax();
    184 }
    Luogu3596 MOD

    Luogu3592 [POI2015]MYJ

    区间DP 

    题解传送门

    Luogu3590[POI2015]TRZ

     Solution

    若子串中只存在一种字符 : $O(N)$扫一遍即可得到答案

    其他情况 : 设sum[i][k] 为前$i$ 个字符中, 字符$k$的个数

    若一个子串$[j + 1, i]$满足题设条件 , 则

      $sum[i][1] - sum[j][1]  != sum[i][2] - sum[j][2]$

      $sum[i][2] - sum[j][2] != sum[i][3] - sum[j][3]$

      $sum[i][3] - sum[j][3] != sum[i][1] - sum[j][1]$

    移项得到 :

      $sum[i][1] - sum[i][2] != sum[j][1] - sum[j][2]$

      $sum[i][2] - sum[i][3] != sum[j][2] - sum[j][3]$

      $sum[i][3] - sum[i][1] != sum[j][3] - sum[j][1]$

    设 $x =  sum[i][1] - sum[i][2], y = sum[i][2] - sum[i][3], z = sum[i][3] - sum[i][1]$

    则要满足 $x_i != x_j, y_i != y_j, z_i != z_j$

    有三维, 直接求解会很麻烦。

    用线段树或者树状数组维护(我不会用树状数组QAQ)

    首先对$x$进行排序, 相同的$x$一起查询更新, 这样就少了一维

    然后以 $y$ 为线段树的下标,

    节点内存储区间的 最小的标号 $i$ ,次小标号,最小标号的 $z$ 值, 最大标号, 次大标号, 最大标号的$z$值

    最后吸氧才过的呜呜呜, 常数太大了

    Code

      1 // luogu-judger-enable-o2
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #define rd read()
      6 #define N 1000005
      7 #define inf 1e8
      8 #define ri register
      9 using namespace std;
     10 
     11 int n, sum[4], ans, ls[N], tot;
     12 char op[N];
     13 
     14 struct P {
     15     int id, x, y, z;
     16 }a[N];
     17 
     18 inline int read() {
     19     int X = 0, p = 1; char c = getchar();
     20     for (; c > '9' || c < '0'; c = getchar())
     21         if (c == '-') p = -1;
     22     for (; c >= '0' && c <= '9'; c = getchar())
     23         X = X * 10 + c - '0';
     24     return X * p;
     25 }
     26 
     27 inline int cmp(const P &A, const P &B) {
     28     return A.x < B.x;
     29 }
     30 
     31 inline void cmax(int &A, int B) {
     32     if (A < B)
     33          A = B;
     34 }
     35 
     36 namespace SegT {
     37 #define mid ((l + r) >> 1)
     38 #define lson x << 1
     39 #define rson x << 1 | 1
     40     struct node {
     41         int maxz, minz, maxn[2], minn[2];
     42         node () {
     43             maxn[0] = maxn[1] = -inf;
     44             minn[0] = minn[1] = inf;
     45             maxz = minz = inf;
     46         }
     47     }pt[N << 2];
     48     
     49     inline void up(node&x, int val, int z) {
     50         if (val > x.maxn[0] && z != x.maxz) {
     51             x.maxn[1] = x.maxn[0];
     52             x.maxn[0] = val;
     53             x.maxz = z;
     54         }
     55         else if (val > x.maxn[0]&& z == x.maxz) {
     56             x.maxn[0] = val;
     57             x.maxz = z;
     58         }
     59         else if (val > x.maxn[1] && z != x.maxz) {
     60             x.maxn[1] = val;
     61         }
     62     }
     63 
     64     inline void down(node &x, int val, int z) {
     65         if (val < x.minn[0] && z != x.minz) {
     66             x.minn[1] = x.minn[0];
     67             x.minn[0] = val;
     68             x.minz = z;
     69         }
     70         else if (val < x.minn[0] && z == x.minz) {
     71             x.minn[0] = val;
     72             x.minz = z;
     73         }
     74         else if (val < x.minn[1] && z != x.minz) {
     75             x.minn[1] = val;
     76         }
     77     }
     78 
     79     node merge(node l, node r) {
     80         node res = l;
     81         up(res, r.maxn[0], r.maxz);
     82         up(res, r.maxn[1], inf);
     83         down(res, r.minn[0], r.minz);
     84         down(res, r.minn[1], inf);
     85         return res;
     86     }
     87 
     88     inline void pushup(int x) {
     89         pt[x] = merge(pt[lson], pt[rson]);
     90     }
     91 
     92     void modify(int pos, int val, int z, int l, int r, int x) {
     93         if (l == r) {
     94             up(pt[x], val, z); down(pt[x], val, z);
     95             return;
     96         }
     97         if (pos <= mid)
     98             modify(pos, val, z, l, mid, lson);
     99         else modify(pos, val, z, mid + 1, r, rson);
    100         pushup(x);
    101     }
    102 
    103     node query(int L, int R, int l, int r, int x) {
    104         if (L <= l && r <= R)
    105             return pt[x];
    106         node res, ltmp, rtmp;
    107         if (L > R) return res;
    108         if (mid >= L)
    109             ltmp = query(L, R, l, mid, lson);
    110         if (mid < R)
    111             rtmp = query(L, R, mid + 1, r, rson);
    112         res = merge(ltmp, rtmp);
    113         return res;
    114     }
    115 }using namespace SegT;
    116 
    117 int main()
    118 {
    119     n = rd; tot = 1;
    120     scanf("%s", op + 1);
    121     for (ri int i = 1, last = 0; i <= n; ++i) {
    122         int typ;
    123         if (op[i] == 'B') typ = 1;
    124         else if (op[i] == 'C') typ = 2;
    125         else typ = 3;
    126         sum[typ]++;
    127         a[i].id = i;
    128         a[i].x = sum[1] - sum[2];
    129         a[i].y = sum[2] - sum[3];
    130         a[i].z = sum[3] - sum[1];
    131         ls[++tot] = a[i].y;
    132         if (typ == last) sum[0]++;
    133         else sum[0] = 1;
    134         cmax(ans, sum[0]);
    135     }
    136     a[0].x = a[0].y = a[0].z = a[0].id = 0;
    137     sort(a, a + 1 + n, cmp);
    138     sort(ls + 1, ls + 1 + tot);
    139     tot = unique(ls + 1, ls + 1 + tot) - ls - 1;
    140     for (ri int i = 0; i <= n; ++i)
    141         a[i].y = lower_bound(ls + 1, ls + 1 + tot, a[i].y) - ls;
    142     a[n + 1].x = inf;
    143     for (ri int i = 0, j = 0; i <= n; i = j + 1) {
    144         for (j = i; j <= n && a[j].x == a[j + 1].x; ++j) {
    145             node ltmp = query(1, a[j].y - 1, 1, tot, 1);
    146             node rtmp = query(a[j].y + 1, tot, 1, tot, 1);
    147             node tmp = merge(ltmp, rtmp);
    148             if (tmp.maxz == a[j].z)
    149                 cmax(ans, tmp.maxn[1] - a[j].id);
    150             else cmax(ans, tmp.maxn[0] - a[j].id);
    151             if (tmp.minz == a[j].z)
    152                 cmax(ans, a[j].id - tmp.minn[1]);
    153             else cmax(ans, a[j].id - tmp.minn[0]);
    154         }
    155 
    156         node ltmp = query(1, a[j].y - 1, 1, tot, 1);
    157         node rtmp = query(a[j].y + 1, tot, 1, tot, 1);
    158         node tmp = merge(ltmp, rtmp);
    159         if (tmp.maxz == a[j].z)
    160             cmax(ans, tmp.maxn[1] - a[j].id);
    161         else cmax(ans, tmp.maxn[0] - a[j].id);
    162         if (tmp.minz == a[j].z)
    163             cmax(ans, a[j].id - tmp.minn[1]);
    164         else cmax(ans, a[j].id - tmp.minn[0]);
    165 
    166         for (j = i; j <= n && a[j].x == a[j + 1].x; ++j) {
    167             modify(a[j].y, a[j].id, a[j].z, 1, tot, 1);
    168         }
    169         modify(a[j].y, a[j].id, a[j].z, 1, tot, 1);
    170     }
    171     printf("%d
    ", ans);
    172 }
    Luogu3590 TRZ

    Luogu3591[POI2015]ODW

    传送门~~

    Luogu3597[POI2015]WYC

    传送门~~

     Luogu3587[POI2015]POD

    不出意外又去看题解了, 是比较套路和有思维的题目

    大佬写的题解简单易懂: 传送门   (https://www.cnblogs.com/five20/p/9581552.html) byfive20

    环形前缀和, 用hash记录每种颜色出现的次数, 在某种颜色的最后一个位置删去该颜色的全部贡献。

    两个hash值相同的位置就是可以分割的点。 因为要$r-l$ 尽可能接近mid ,能用单调队列来维护。


    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define rd read()
     5 #define ll long long
     6 #define R register
     7 using namespace std;
     8 
     9 const int N = 1000005, base1 = 999979, base2 = 999983, mod1 = 1e9 + 7, mod2 = 1e9 + 9;
    10 
    11 ll po1[N], po2[N], sum1, sum2;
    12 int last[N], cnt[N], n, k, a[N];
    13 
    14 struct node {
    15     int id;
    16     ll s1, s2;
    17 }b[N];
    18 
    19 inline int read() {
    20     int X = 0, p = 1; char c = getchar();
    21     for (; c > '9' || c < '0'; c = getchar())
    22         if (c == '-') p = -1;
    23     for (; c >= '0' && c <= '9'; c = getchar())
    24         X = X * 10 + c - '0';
    25     return X * p;
    26 }
    27 
    28 int cmp(const node &A, const node &B) {
    29     if (A.s1 != B.s1) return A.s1 < B.s1;
    30     if (A.s2 != B.s2) return A.s2 < B.s2;
    31     return A.id < B.id;
    32 }
    33 
    34 int jud(int x, int y) {
    35     if (b[x].s1 != b[y].s1) return 0;
    36     if (b[x].s2 != b[y].s2) return 0;
    37     return 1;
    38 }
    39 
    40 void cmin(int &A, int B) {
    41     if (A > B) A = B;
    42 }
    43 
    44 int Abs(int A) {
    45     return A > 0 ? A : -A;
    46 }
    47 
    48 int main()
    49 {
    50     n = rd; k = rd;
    51     for (R int i = 1; i <= n; ++i)
    52         a[i] = rd;
    53     po1[0] = po2[0] = 1;
    54     for (R int i = 1; i <= k; ++i)
    55         po1[i] = po1[i - 1] * base1 % mod1,
    56         po2[i] = po2[i - 1] * base2 % mod2;
    57     for (R int i = 1; i <= n; ++i) 
    58         cnt[a[i]]++, last[a[i]] = i;
    59     for (R int i = 1; i <= n; ++i) {
    60         (sum1 += po1[a[i]]) %= mod1;
    61         (sum2 += po2[a[i]]) %= mod2;
    62         if (i == last[a[i]]) 
    63             sum1 = (sum1 - po1[a[i]] * cnt[a[i]] % mod1) % mod1,
    64             sum1 = (sum1 + mod1) % mod1,
    65             sum2 = (sum2 - po2[a[i]] * cnt[a[i]] % mod2) % mod2,
    66             sum2 = (sum2 + mod2) % mod2;
    67         b[i].id = i,
    68         b[i].s1 = sum1,
    69         b[i].s2 = sum2;
    70     }
    71     sort(b + 1, b + 1 + n, cmp);
    72     ll ans1 = 0; int ans2 = n;
    73     int mid = (n + 1) >> 1;
    74     for (int i = 1, j = 1; i <= n; i = j) {
    75         while (j <= n && jud(i, j)) j++;
    76         ans1 += 1LL * (j - i) * (j - i - 1) / 2;
    77         for (int l = i, r = i; r < j; ++r) {
    78             while (l < r && b[r].id - b[l].id >= mid) l++;
    79             cmin(ans2, Abs(n - 2 * (b[r].id - b[l].id)));
    80             if (l != i) 
    81                 cmin(ans2, Abs(n - 2 * (b[r].id - b[l - 1].id)));
    82         }
    83     }
    84     printf("%lld %d
    ", ans1, ans2);
    85 }
    Luogu3587 POD

    Luogu3589[POI2015]KUR

    神奇的传送门~

  • 相关阅读:
    如何在java类中读取Properties配置文件
    常用网址 转
    我的读书计划
    制作一个半透明遮罩层的库——TipView
    RxJava 中的 subscribeOn 和 observeOn 的区别
    一个操作SQLite数据库的例子
    Java ThreadLocal
    3. 请求与响应
    Java的Volatile关键字
    排序
  • 原文地址:https://www.cnblogs.com/cychester/p/9820393.html
Copyright © 2020-2023  润新知