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 rl+1<k.

Give you k , you need to calculate nl=1nr=lf(l,r,k)

There are T test cases.

1T10

kmin(n,80)

A[1..n] is a permutation of [1..n]

n5105
 
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]
 
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;
}

 

posted @ 2017-08-05 10:52  茶飘香~  阅读(308)  评论(0编辑  收藏  举报