HDU 6058 Kanade's sum(链表)

来源:互联网 发布:搜狗高速浏览器mac版 编辑:程序博客网 时间:2024/05/21 13:38
#include<cstdio>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;/*链表给定一个长度为n的数列,求所有区间第k大的数之和*/const int maxn=5e5+5;int n,k;int a[maxn],pos[maxn];int pre[maxn],nex[maxn];bool cmp(int x,int y){    return a[x]<a[y];}int main(){    int T;    int kase=1;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&k);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        for(int i=0;i<=n+1;i++)        {            pre[i]=i-1;            nex[i]=i+1;            pos[i]=i;        }        sort(pos+1,pos+1+n,cmp);        LL ans=0;        for(int i=1;i<=n;i++)        {            int pl=pos[i];            int pr=pos[i];            int cnt=0;            //直接找k-1个数,这k-1个数都是比当前遍历的这个数大,            //因为通过不断维护链表,保证当前遍历的数是链中最小的数            while(cnt<k-1&&pre[pl]>0)            {                cnt++;                pl=pre[pl];            }            while(cnt<k-1&&nex[pr]<=n)            {                cnt++;                pr=nex[pr];            }            if(cnt==k-1)            {                while(pl!=nex[pos[i]]&&pr<=n)//最左不超过当前这个数的位置,最右不超过n                {                    //pl-pre[pl] nex[pr]-pr 之间的差为原始数列中                    //[pl.pre[pl] ] [next[pr],pr]区间之间小于当前遍历的数的数量                    ans+=(LL)i*abs(pl-pre[pl])*abs(nex[pr]-pr);                    printf("i=%d pl=%d pre=%d pr=%d nex=%d\n",i,pl,pre[pl],pr,nex[pr]);                    pl=nex[pl];                    pr=nex[pr];                }            }            //从小到大,依次删除元素,比某个数小的数不会影响该数成为第K大            //删除当前遍历的数            pl=pre[pos[i]];            pr=nex[pos[i]];            pre[pr]=pl;            nex[pl]=pr;        }        printf("%I64d\n",ans);    }    return 0;}