hdu6058[链表维护] 2017多校3

用一个双向链表来查找比当前元素大的前k-1个元素和后k-1个元素 ,从小到大枚举x,算完x的贡献后将x从链表中删除,优化到O(nk)。

/*hdu6058[链表维护] 2017多效3*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int T, n, k, temp;
int pos[500005], pre[500005], nxt[500005];
LL a[500005], b[500005];
LL ans = 0;
LL Getans(int x) {
    int r1 = 0, r2 = 0;
    LL ret = 0;
    for (int i = x; i >= 0 && r1 <= k; i = pre[i]) {
        a[++r1] = i - pre[i];//向前找k-1个比当前元素大的
    }
    for (int i = x; i <= n && r2 <= k; i = nxt[i]) {
        b[++r2] = nxt[i] - i;//向后找k-1个比当前元素大的
    }
    for (int i = 1; i <= r1; i++) {
        if (k - i + 1 <= r2 && k - i + 1 >= 1) {
            //cout << x << ' ' << a[i] << ' ' << b[k - i + 1] << endl;
            ret += a[i] * b[k - i + 1];
        }
    }
    return ret;
}
void del(int i) {
    pre[nxt[i]] = pre[i];
    nxt[pre[i]] = nxt[i];
}
void connect(int u, int v) {
    nxt[u] = v;
    pre[v] = u;
}
void solve() {
    for (int i = 0; i <= n; i++)
        connect(i, i + 1);
    for (int i = 1; i <= n; i++) {
        ans += Getans(pos[i]) * i;
        del(pos[i]);//每次删去一个, 保证其他所有元素都比当前元素大
    }
    printf("%lld\n", ans);
}
int main() {
    scanf("%d", &T);
    while (T--) {
        ans = 0;
        scanf("%d %d", &n, &k);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &temp);
            pos[temp] = i;
        }
        solve();
    }
    return 0;
}

 

posted @ 2017-08-02 13:44  UnderSilence  阅读(160)  评论(0编辑  收藏  举报