hdu 6058---Kanade's sum(链表)
Problem Description
Give you an array A[1..n]of length n.
Let f(l,r,k) be the k-th largest element of A[l..r].
Specially , f(l,r,k)=0 if r−l+1<k.
Give you k , you need to calculate ∑nl=1∑nr=lf(l,r,k)
There are T test cases.
1≤T≤10
k≤min(n,80)
A[1..n] is a permutation of [1..n]
∑n≤5∗105
Let f(l,r,k) be the k-th largest element of A[l..r].
Specially , f(l,r,k)=0 if r−l+1<k.
Give you k , you need to calculate ∑nl=1∑nr=lf(l,r,k)
There are T test cases.
1≤T≤10
k≤min(n,80)
A[1..n] is a permutation of [1..n]
∑n≤5∗105
Input
There is only one integer T on first line.
For each test case,there are only two integers n,k on first line,and the second line consists of n integers which means the array A[1..n]
For each test case,there are only two integers n,k on first line,and the second line consists of n integers which means the array A[1..n]
Output
For each test case,output an integer, which means the answer.
Sample Input
1
5 2
1 2 3 4 5
Sample Output
30
题意:输入n,k 然后输入n个数(1~n的排列),求所有子区间的第k大数之和(长度小于k的区间值为0)。
思路:考虑每个数的贡献值,对于每个数求有多少个区间的第k大数是它,所以我们需要求出每个数向左比它大的k个数的位置,向右比它大的k个数的位置,根据这些位置就可以算出有多少区间它是第k大(这个就不详细说了),那么怎么求向左向右比它大的k数的位置呢,直接求复杂度比较高,我们可以按照1~n的数值大小顺序求向左向右的比它大的k个数的位置,用链表维护,算完i之后,将i从链表里面删除,那么剩余的都是比i+1大的数了,所以直接向左右遍历k个数即可。
代码如下:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; const int N=5e5+5; struct Node { int x; int l,r; }t[N]; int a[N], L[85], R[85]; int main() { int T,n,k; cin>>T; while(T--) { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&t[i].x); t[i].l=i-1; t[i].r=i+1; a[t[i].x]=i; } t[1].l=-1; t[n].r=-1; LL ans=0; for(int i=1;i<=n;i++) { //ans=0; int pos=a[i]; int tot=0;///右 for(int j=t[pos].r;j!=-1;j=t[j].r) { R[++tot]=j; if(tot>=k) break; } R[0]=tot; if(tot<k) R[tot+1]=n+1; tot=0; ///左 for(int j=t[pos].l;j!=-1;j=t[j].l) { L[++tot]=j; if(tot>=k) break; } L[0]=tot; if(tot<k) L[tot+1]=0; int l=t[pos].l; int r=t[pos].r; if(l>0) t[l].r=r; if(r>0) t[r].l=l; for(int j=L[0]; j>=0; j--) { if(j>=k) continue; int x=k-1-j; if(x>R[0]) continue; int l=L[j]-L[j+1]; if(j==0) l=pos-L[1]; int r=R[x+1]-R[x]; if(x==0) r=R[1]-pos; ans+=(LL)l*(LL)r*(LL)t[pos].x; } } printf("%lld\n",ans); } return 0; }