2019 Multi-University Training Contest 10 - Make Rounddog Happy

分治 + ST表

先预处理出区间内最大值的位置和每个数向左和向右能够延伸的最大距离。

然后把每个区间的最大值的位置当成中点来分治统计每个数的贡献。

统计的时候选区间较短的统计,类似于启发式合并?

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
#define __fastIn ios::sync_with_stdio(false), cin.tie(0)
#define pb push_back
using namespace std;
using LL = long long;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
    int ret = 0, w = 0; char ch = 0;
    while(!isdigit(ch)){
        w |= ch == '-', ch = getchar();
    }
    while(isdigit(ch)){
        ret = (ret << 3) + (ret << 1) + (ch ^ 48);
        ch = getchar();
    }
    return w ? -ret : ret;
}
template <typename A>
inline A __lcm(A a, A b){ return a / __gcd(a, b) * b; }
template <typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
    A ans = 1;
    for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
    return ans;
}
const int N = 300005;
int _, n, k, a[N], L[N], R[N], pos[N], lb[N], st[N][25];
LL ans;

void initST(){
    for(int i = 1; i <= n; i ++) st[i][0] = i;
    for(int j = 1; j <= 20; j ++){
        for(int i = 1; i + (1 << j) - 1 <= n; i ++){
            int p = st[i][j - 1], q = st[i + (1 << (j - 1))][j - 1];
            st[i][j] = a[p] > a[q] ?  p : q;
        }
    }
}

int query(int l, int r){
    int t = lb[r - l + 1];
    int p = st[l][t], q = st[r - (1 << t) + 1][t];
    return a[p] > a[q] ? p : q;
}

void solve(int l, int r){
    if(l > r) return;
    int mid = query(l, r);
    solve(l, mid - 1), solve(mid + 1, r);

    int x = a[mid] - k;
    if(mid - l < r - mid){
        for(int i = l; i <= mid; i ++){
            int lower = max(i + x - 1, mid);
            int upper = min(R[i], r);
            if(upper >= lower) ans += upper - lower + 1;
        }
    }
    else{
        for(int i = mid; i <= r; i ++){
            int lower = min(i - x + 1, mid);
            int upper = max(L[i], l);
            if(upper <= lower) ans += lower - upper + 1;
        }
    }
}

int main(){

    lb[0] = -1; for(int i = 1; i < N; i ++) lb[i] = lb[i >> 1] + 1;
    for(_ = read(); _; _ --){
        ans = 0;
        n = read(), k = read();
        for(int i = 1; i <= n; i ++) a[i] = read();
        for(int i = 1; i <= n; i ++) pos[i] = 0;
        for(int i = 1; i <= n; i ++){
            L[i] = pos[a[i]] + 1;
            pos[a[i]] = i;
        }
        for(int i = 2; i <= n; i ++){
            L[i] = max(L[i - 1], L[i]);
        }
        for(int i = 1; i <= n; i ++) pos[i] = n + 1;
        for(int i = n; i >= 1; i --){
            R[i] = pos[a[i]] - 1;
            pos[a[i]] = i;
        }
        for(int i = n - 1; i >= 1; i --){
            R[i] = min(R[i + 1], R[i]);
        }
        initST();
        solve(1, n);
        printf("%lld\n", ans);
    }
    return 0;
}
posted @ 2019-08-22 20:49  清楚少女ひなこ  阅读(141)  评论(0编辑  收藏  举报