HDU6058 Kanade's sum【模拟】

来源:互联网 发布:淘宝联盟可以注销吗 编辑:程序博客网 时间:2024/06/05 22:52

题意:找所有区间的第k大值,没有第k大就是0,求和


思路:我们需要一个链表,记录每个位置左右比他大的数的第一个位置。n从大到小枚举,我们用set存放比它大的数的坐标,查找距离它最近的位置,更新链表。我们在这个位置左右找比它大的k-1个值,那这个位置就是第k大的。找到这些区间即可。


#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<stdlib.h>#include<math.h>#include<vector>#include<list>#include<map>#include<stack>#include<queue>#include<set>#include<algorithm>#include<numeric>#include<functional>using namespace std;typedef long long ll;const int maxn = 5e5+5;set<int> s;set<int>::iterator iter;int a[maxn],vis[maxn],le[maxn],ri[maxn];int main(void){int n,k,i,j,T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&k);s.clear();memset(le,-1,sizeof le);memset(ri,-1,sizeof ri);for(i = 1; i <= n; i++){scanf("%d",&a[i]);le[i] = 0;ri[i] = n + 1;vis[a[i]] = i;}s.insert(0);s.insert(n+1);le[n+1] = 0;ri[0] = n + 1;long long ans = 0;for(i = n; i >= 1; i--){int l,r;s.insert(vis[i]);iter = s.find(vis[i]);iter++;r = *iter;l = le[r];ri[l] = vis[i];ri[vis[i]] = r;le[r] = vis[i];le[vis[i]] = l;int nowl,nowr;nowl = vis[i];int cnt = 0;while(cnt < k && nowl != 0){nowl = le[nowl];cnt++;}nowr = vis[i];while(cnt < k && nowr != n+1){nowr = ri[nowr];cnt++;}if(cnt < k)continue;int nl = ri[nowl],nr = ri[nowr];while(nowl < vis[i] && nowr < n+1){ans += 1ll * (nl-nowl) * (nr - nowr) * i;nowl = ri[nowl];nowr = ri[nowr];nl = ri[nowl],nr = ri[nowr];}}printf("%lld\n",ans);}return 0;}