luogu P5070 [Ynoi2015] 即便看不到未来

https://www.luogu.com.cn/problem/P5070

感觉YNOI polylog题都挺有趣的
首先还是考虑离线下来扫描线
按右端点离线

记上一个 x x x出现的位置为 p r e [ x ] pre[x] pre[x]
考虑新加一个 x x x,显然对左端点在 p r e [ x ] pre[x] pre[x]之前的区间是没有单独的贡献的
因为要求长度在10以内的极长连续段个数,所以可以考虑把 [ x − 11 , x + 11 ] [x-11,x+11] [x11,x+11]的上一次的出现位置(在pre[x]之后的)全部拿出来,从大到小排序,一个个加进去
考虑加入x后可能会发生的情况

  • 在某个连续段段开头接上
  • 在某个连续段段结尾接上
  • 把两个连续段合并在一起
    每次只需加上第三种情况减去前两种情况的贡献即可
    可以用树状数组维护后缀和,区间加,单点询问

代码不难实现
code:

#include<bits/stdc++.h>
#define N 1000050
using namespace std;
#define lowbit(x) (x & -x)
struct TT {
    int t[N];
    void update(int x, int y) {
        for(; x; x -= lowbit(x)) t[x] += y;
    }
    int query(int x) {
        int ret = 0;
        for(; x < N; x += lowbit(x)) ret += t[x];
        return ret;
    }
} t[13];
struct Q {
    int l, id;
} ;
vector<Q> q[N];
int pre[N], a[N], n, m, id[N], vis[N], ans[N][13];
int cmp(int x, int y) {
    return pre[x] > pre[y];
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    for(int i = 1; i <= m; i ++) {
        int l, r;
        scanf("%d%d", &l, &r);
        q[r].push_back((Q){l, i});
    }
    for(int r = 1; r <= n; r ++) {
        int ll = max(1, a[r] - 11), rr = a[r] + 11, gs = 0;
        for(int i = ll; i <= rr; i ++) if(pre[i] >= pre[a[r]]) id[++ gs] = i;
        sort(id + 1, id + 1 + gs, cmp);
        t[1].update(r, 1), t[1].update(pre[id[1]], -1);
        int L = 0, R = 0;
        for(int i = 1; i < gs; i ++) {
            vis[id[i]] = 1;
            while(vis[a[r] - L - 1]) L ++;
            while(vis[a[r] + R + 1]) R ++;
            int U = min(L + R + 1, 11);
            t[L].update(pre[id[i]], -1), t[L].update(pre[id[i + 1]], 1);
            t[R].update(pre[id[i]], -1), t[R].update(pre[id[i + 1]], 1);
            t[U].update(pre[id[i]], 1), t[U].update(pre[id[i + 1]], -1);
        }
        for(int i = ll; i <= rr; i ++) vis[i] = 0;
        for(int i = 0; i < q[r].size(); i ++)
            for(int j = 1; j <= 10; j ++)
                ans[q[r][i].id][j] = t[j].query(q[r][i].l);
        
        pre[a[r]] = r;
    }
    for(int i = 1; i <= m; i ++) {
        for(int j = 1; j <= 10; j ++) printf("%d", ans[i][j] % 10); printf("\n");
    }
    return 0;
}
posted @ 2021-09-01 07:31  lahlah  阅读(39)  评论(0编辑  收藏  举报