HDU-6701はRounddog幸せにします

トピックリンク

Rounddog幸せを作ります

問題の説明

Rounddogは常に、⋯、配列A1、A2を持っている彼の右ポケットに、1≤ai≤nを満たします。

サブアレイは、元の配列の非空のサブセグメントです。(R-L + 1)≤k - Rounddogはサブセグメントら、ら+ 1、⋯として良好なサブアレイを定義し、その中のすべての要素が異なるとmax(AL、ら+ 1、...、AR)はアーカンソー。

Rounddogは今日幸せではありません。彼の親友として、あなたは彼を幸せにするために、すべての良いサブアレイを見つけたいです。この場合、の良いサブアレイの合計数を計算してください。

入力

入力は、いくつかのテストケースを含み、最初の行は、単一の整数T(1≤T≤20)、テストケースの数を含んでいます。

各テストケースの最初の行は、二つの整数N(1≤n≤300000)及びk(1≤k≤300000)を含みます。

2行目は、AI(1≤ai≤n)はi番目れたn個の整数を含んでいます。

すべてのテストケースの上に、nの合計は1000000を超えることはないことが保証されています。

出力

Rounddogが好きサブアレイの数を表す各テストケースのために一つの整数、。

サンプル入力

2
5 3
2 3 2 2 5
10 4
1 5 4 3 6 2 10 8 4 5

サンプル出力

7
31

問題の意味

与えられたkのアレイ、Qの数\(L、Rの\)を満足\(MAX(AL、ら+ 1、...、アーカンソー州) - (R-L + 1)≤k\)

問題の解決策

各パーティションヒューリスティック間隔、示さ間隔横断することによって最大制御\([L、R&LT] \) 左部の方が小さい場合は、中間位置での最大値は、左部で算出され、左部を横切ります[i]はiは右私はプレ場合、まで延び表すとプログラムの数が予めアレイは予め、そうでない場合は右の横断部、エンドポイントが残っている各点[i]の数値は繰返さない、SUF [i]を表します。 SUF [i]がI番号に繰返さない、およびO(1)プログラム番号の左端点で各点について計算することができるので、私は、左まで延びている場合。全体的な複雑さ\(O(N \ログN )\)

コード

#include <bits/stdc++.h>
using namespace std;
const int mx = 3e5+5;
int a[mx], pre[mx], suf[mx];
int n, k;
bool vis[mx];

struct Node {
    int v, pos;
}tree[mx<<2];
 
void pushUp(int rt) {
    tree[rt].v = max(tree[rt<<1].v, tree[rt<<1|1].v);
    tree[rt].pos = (tree[rt<<1].v > tree[rt<<1|1].v ? tree[rt<<1].pos : tree[rt<<1|1].pos);
}
 
void build(int l, int r, int rt) {
    if (l >= r) {
        tree[rt].v = a[r];
        tree[rt].pos = r;
        return;
    }
    int mid = (l + r) / 2;
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushUp(rt);
}
 
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return tree[rt].pos;
    int mid = (l + r) / 2;
    int pos1 = -1, pos2 = -1;
    if (L <= mid) pos1 = query(L, R, l, mid, rt<<1);
    if (mid < R) pos2 = query(L, R, mid+1, r, rt<<1|1);
    if (pos1 == -1) return pos2;
    else if (pos2 == -1) return pos1;
    else return a[pos1] > a[pos2] ? pos1 : pos2;
}

void dfs(int l, int r, long long &ans) {
    if (l > r) return;
    int mid = query(l, r, 1, n, 1);
    int len = max(1, a[mid]-k);
    if (mid-l <= r-mid) {
        for (int i = l; i <= mid; i++) {
            int L = max(mid, i+len-1);
            int R = min(pre[i], r);
            ans += max(0, R-L+1);
        }
    } else {
        for (int i = mid; i <= r; i++) {
            int R = min(mid, i-len+1);
            int L = max(suf[i], l);
            ans += max(0, R-L+1);
        }
    }
    dfs(l, mid-1, ans);
    dfs(mid+1, r, ans);
}

int main() {
    int T;
    scanf("%d", &T);

    while (T--) {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        build(1, n, 1);
        int pos = 0;
        for (int i = 1; i <= n; i++) {
            while (pos < n && !vis[a[pos+1]]) {
                pos++;
                vis[a[pos]] = true;
            }
            pre[i] = pos;
            vis[a[i]] = false;
        }
        pos = n+1;
        for (int i = n; i >= 1; i--) {
            while (pos > 1 && !vis[a[pos-1]]) {
                pos--;
                vis[a[pos]] = true;
            }
            suf[i] = pos;
            vis[a[i]] = false;
        }
        
        long long ans = 0;
        dfs(1, n, ans);
        printf("%lld\n", ans);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/bpdwn-cnblogs/p/11392039.html