zoukankan      html  css  js  c++  java
  • Codeforces 765F Souvenirs

    题目传送门

      神速的列车

      光速的列车

      声速的列车

    题目大意

      给定一个长度为$n$的序列,$m$次询问区间$[l, r]$内相差最小的两个数的差的绝对值。

    Solution 1 Mo's Algorithm & Linked List

      不会。。果断莫队

      当插入一个数的时候,如果用set维护前驱后继,然后结果是:$O((n + m)sqrt{n}log n)$,没救的,卡不过去。

      但是感觉原序列不会改变,使用set维护很浪费。

      考虑链表,链表上的每个数的后继是这个数的后继。

      考虑可以通过排序提前得到大小关系,不断从链表中删数就能得到它在剩下的区间内的前后继。如果询问在同一个块内直接暴力。否则把答案分成三部分。

    • 两个数都在当前块外,先从小到大加入剩下的所有数,从右到左删掉它们,再从左到右不断加入它们,然后就能得到所有前缀的答案。
    • 两个数都在当前块内,处理出所有后缀的答案,做法类似。
    • 一个在当前块内,一个在块外,移动右指针的时候让块内的所有数在链表内,查询的时候删掉再加入。

    Code

      1 /**
      2  * Codeforces
      3  * Problem#765F
      4  * Accepted
      5  * Time: 1309ms
      6  * Memory: 9400k
      7  */ 
      8 #include <bits/stdc++.h>
      9 using namespace std;
     10 typedef bool boolean;
     11 
     12 #define pii pair<int, int>
     13 #define fi first
     14 #define sc second
     15 
     16 const int cs = 350;
     17 const signed int inf = (signed) (~0u >> 1);
     18 
     19 typedef class Query {
     20     public:
     21         int l, r, lid, rid, id, res;
     22         
     23         boolean operator < (Query b) const {
     24             if (lid != b.lid)    return lid < b.lid;
     25             return r < b.r;
     26         }
     27 }Query;
     28 
     29 int n, m;
     30 int *ar;
     31 pii *cr;
     32 int *pre, *suf, *L;
     33 Query *qs;
     34 
     35 inline void init() {
     36     scanf("%d", &n);
     37     ar = new int[(n + 1)];
     38     cr = new pii[(n + 1)];
     39     pre = new int[(n + 2)];
     40     suf = new int[(n + 2)];
     41     L = new int[(n + 1)];
     42     for (int i = 1; i <= n; i++)
     43         scanf("%d", ar + i), cr[i].fi = ar[i], cr[i].sc = i;
     44     scanf("%d", &m);
     45     qs = new Query[(m + 1)];
     46     for (int i = 1; i <= m; i++) {
     47         scanf("%d%d", &qs[i].l, &qs[i].r);
     48         qs[i].lid = (qs[i].l - 1) / cs, qs[i].rid = (qs[i].r - 1) / cs;
     49         qs[i].id = i;
     50     }
     51 }
     52 
     53 void add(int p) {
     54     suf[pre[p]] = p;
     55     pre[suf[p]] = p;
     56 }
     57 
     58 void remove(int p) {
     59     suf[pre[p]] = suf[p];
     60     pre[suf[p]] = pre[p];
     61 }
     62 
     63 int update(int p) {
     64     int rt = inf;
     65     if (pre[p])
     66         rt = ar[p] - ar[pre[p]];
     67     if (suf[p] <= n)
     68         rt = min(rt, ar[suf[p]] - ar[p]);
     69     return rt;
     70 }
     71 
     72 inline void solve() {
     73     sort(cr + 1, cr + n + 1);
     74     sort(qs + 1, qs + m + 1);
     75     int c = 1;
     76     for (int sid = 0; sid <= n / cs && c <= m; sid++) {
     77         int mdzzr = min(cs * (sid + 1), n), ls = 0, lr = cs * sid, ce = mdzzr;
     78         
     79         pre[0] = 0, ls = 0;
     80         for (int i = 1; i <= n; i++) {
     81             pre[cr[i].sc] = ls;
     82             suf[ls] = cr[i].sc;
     83             ls = cr[i].sc;
     84         }
     85         suf[n + 1] = n + 1, pre[n + 1] = ls, suf[ls] = n + 1;
     86         
     87         for (int i = 1; i <= mdzzr; i++)
     88             remove(i);
     89         for (int i = n; i > mdzzr; i--)
     90             remove(i);
     91         L[mdzzr] = inf;
     92         for (int i = mdzzr + 1; i <= n; i++)
     93             add(i), L[i] = min(L[i - 1], update(i));
     94         for (int i = mdzzr; i > lr; i--)
     95             add(i);
     96         for (int i = n; i > mdzzr; i--)
     97             remove(i);
     98         
     99         for ( ; c <= m && qs[c].lid == sid; c++) {
    100             int l = qs[c].l, r = qs[c].r;
    101             if (qs[c].lid == qs[c].rid) {
    102                 for (int i = lr + 1; i < l; i++)
    103                     remove(i);
    104                 for (int i = mdzzr; i >= l; i--)
    105                     remove(i);
    106                 int res = inf;
    107                 for (int i = l; i <= r; i++)
    108                     add(i), res = min(res, update(i));
    109                 for (int i = r + 1; i <= mdzzr; i++)
    110                     add(i);
    111                 for (int i = l - 1; i > lr; i--)
    112                     add(i);
    113                 qs[c].res = res;
    114             } else {
    115                 while (mdzzr < r)
    116                     add(++mdzzr);
    117                 int res = inf;
    118                 for (int i = lr + 1; i <= ce; i++)
    119                     remove(i);
    120                 for (int i = ce; i >= l; i--)
    121                     add(i), res = min(res, update(i));
    122                 for (int i = l - 1; i > lr; i--)
    123                     add(i);
    124                 qs[c].res = min(res, L[r]);
    125             }
    126         }
    127     }
    128 
    129     for (int i = 1; i <= m; i++)
    130         while (qs[i].id != i)
    131             swap(qs[i], qs[qs[i].id]);
    132     for (int i = 1; i <= m; i++)
    133         printf("%d
    ", qs[i].res);
    134 }
    135 
    136 int main() {
    137     init();
    138     solve();    
    139     return 0;
    140 }
    Mo's Algorithm

    Solution 2 Segment Tree

      考虑将询问离线,然后分别考虑大于等于位置$i$上的数和小于等于它的数产生的贡献。从左到右扫描数组。

      假设当前考虑以$r$为右端点的询问区间的答案。那么就要将$r$能产生的贡献计算出来。

      能产生贡献的位置是在$r$前大于等于$a_r$的一个递减数列(从后向前)。根据它的期望长度是$log_{n}$的,用个线段树区间取min,就可以水掉bzoj上面的某道题。

      于是cf上成功T掉了。

      加一个很强的剪枝:新找到的数和$a_r$的差必须小于上一个找到的差的一半。

      为什么是正确的呢?因为包含新找到的这个位置和$r$的区间一定包含上一个找到的数,但是显然新找到的数和上一个找到的数的差更优,会在另一次扫描中被统计。

      至于查找上一个在某个值域内最后出现的数的位置,再开一棵线段树。

    Code

      1 /**
      2  * Codeforces
      3  * Problem#765F
      4  * Accepted
      5  * Time: 997ms
      6  * Memory: 28600k
      7  */
      8 #include <algorithm>
      9 #include <iostream>
     10 #include <cstdlib>
     11 #include <cstdio>
     12 using namespace std;
     13 typedef bool boolean;
     14 
     15 const signed int inf = (signed) (~0u >> 1), Val = 1e9;
     16 
     17 typedef class SegTreeNode {
     18     public:
     19         int val;
     20         SegTreeNode *l, *r;
     21 
     22         SegTreeNode() {    }
     23 
     24         void pushUp() {
     25             if (l)
     26                 val = l->val;
     27             if (r)
     28                 val = max(val, r->val);
     29         }
     30 }SegTreeNode;
     31 
     32 SegTreeNode pool[2000000];
     33 SegTreeNode *top = pool;
     34 
     35 SegTreeNode* newnode() {
     36     top->l = top->r = NULL;
     37     return top++;
     38 }
     39 
     40 typedef class SegTree {
     41     public:
     42         SegTreeNode* rt;
     43 
     44         SegTree():rt(NULL) {    }
     45 
     46         void update(SegTreeNode*& p, int l, int r, int ql, int qr, int val) {
     47             if (!p)
     48                 p = newnode(), p->val = inf;
     49             if (l == ql && r == qr)    {
     50                 p->val = min(p->val, val);
     51                 return ;
     52             }
     53             int mid = (l + r) >> 1;
     54             if (qr <= mid)
     55                 update(p->l, l, mid, ql, qr, val);
     56             else if (ql > mid)
     57                 update(p->r, mid + 1, r, ql, qr, val);
     58             else {
     59                 update(p->l, l, mid, ql, mid, val);
     60                 update(p->r, mid + 1, r, mid + 1, qr, val);
     61             }
     62         }
     63 
     64         int query(SegTreeNode *p, int l, int r, int idx) {
     65             if (!p)
     66                 return inf;
     67             if (l == r)
     68                 return p->val;
     69             int mid = (l + r) >> 1, a = p->val, b = 0;
     70             if (idx <= mid)
     71                 b = query(p->l, l, mid, idx);
     72             else
     73                 b = query(p->r, mid + 1, r, idx);
     74             return min(a, b);
     75         }
     76 
     77         void update(SegTreeNode* &p, int l, int r, int idx, int val) {
     78             if (!p)
     79                 p = newnode(), p->val = -1;
     80             if (l == r) {
     81                 p->val = val;
     82                 return;
     83             }
     84             int mid = (l + r) >> 1;
     85             if (idx <= mid)
     86                 update(p->l, l, mid, idx, val);
     87             else
     88                 update(p->r, mid + 1, r, idx, val);
     89             p->pushUp();
     90         }
     91 
     92         int query(SegTreeNode* p, int l, int r, int ql, int qr) {
     93             if (!p)
     94                 return -1;
     95             if (l == ql && r == qr)
     96                 return p->val;
     97             int mid = (l + r) >> 1;
     98             if (qr <= mid)
     99                 return query(p->l, l, mid, ql, qr);
    100             if (ql > mid)
    101                 return query(p->r, mid + 1, r, ql, qr);
    102             int a = query(p->l, l, mid, ql, mid);
    103             int b = query(p->r, mid + 1, r, mid + 1, qr);
    104             return max(a, b);
    105         }
    106 }SegTree;
    107 
    108 typedef class Query {
    109     public:
    110         int l, r, id, res;
    111 
    112         boolean operator < (Query b) const {
    113             return r < b.r;
    114         }
    115 }Query;
    116 
    117 int n, m;
    118 int *ar;
    119 SegTree st, stv;
    120 Query* qs;
    121 
    122 inline void init() {
    123     scanf("%d", &n);
    124     ar = new int[(n + 1)];
    125     for (int i = 1; i <= n; i++)
    126         scanf("%d", ar + i);
    127     scanf("%d", &m);
    128     qs = new Query[(m + 1)];
    129     for (int i = 1; i <= m; i++) {
    130         scanf("%d%d", &qs[i].l, &qs[i].r);
    131         qs[i].id = i, qs[i].res = inf;
    132     }
    133 }
    134 
    135 inline void solve() {
    136     sort(qs + 1, qs + m + 1);
    137     for (int s = 0, c = 0; s < 2; s++) {
    138         st.rt = stv.rt = NULL, top = pool, c = 1;
    139         for (int i = 1; i <= n; i++) {
    140             int rlim = Val, idx;
    141             while (ar[i] <= rlim && (idx = stv.query(stv.rt, 0, Val, ar[i], rlim)) != -1) {
    142                 st.update(st.rt, 1, n, 1, idx, ar[idx] - ar[i]);
    143                 rlim = ((ar[idx] + ar[i] - 1) >> 1);
    144             }
    145             stv.update(stv.rt, 0, Val, ar[i], i);
    146             for ( ; c <= m && qs[c].r == i; c++)
    147                 qs[c].res = min(qs[c].res, st.query(st.rt, 1, n, qs[c].l));
    148         }
    149         for (int i = 1; i <= n; i++)
    150             ar[i] = Val - ar[i];
    151     }
    152     
    153     for (int i = 1; i <= m; i++)
    154         while (qs[i].id != i)
    155             swap(qs[i], qs[qs[i].id]);
    156     for (int i = 1; i <= m; i++)
    157         printf("%d ", qs[i].res);
    158 }
    159 
    160 int main() {
    161     init();
    162     solve();
    163     return 0;
    164 }
  • 相关阅读:
    IDEA 删除java类的3种提示
    IDEA类和方法注释模板设置(非常详细)
    IntelliJ IDEA 2019,从入门到疯狂,图文教程
    intellij idea 如何将普通项目转换为maven项目
    使用idea误点 Add as Ant Build File选项后
    idea使用"svn"到项目报错Error:Cannot run program "svn" (in directory "E:XXXXXX"):CreateProcess error=2,
    Alertmanager 部署配置
    Prometheus PromQL 简单用法
    Prometheus PromQL 基础
    Prometheus 自动发现
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9278425.html
Copyright © 2011-2022 走看看