码迷,mamicode.com
首页 > 其他好文 > 详细

6058 Kanade's sum 链表维护()

时间:2017-08-02 14:22:58      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:--   i++   can   lld   一个   开始   color   its   scanf   

题意:给出元素为[1,n]的排列a,定义f[l,r,k]为区间[l,r]内第k大的元素.
给出k,求 累加和(l=1~n,r~l~n)f[l,r,k] . n<=5e5,k<=min(80,n)
k<=80 a[i]贡献: 枚举左边有p个比它大,右边要有k-1-p个比它大.
如何处理出左/右边第p个比它大的位置?
从最小的数开始处理,链表初始满链,维护一个链表,当处理x时,链表中只有比x大的数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int a[N],b[N],n,k;
int pre[N],nxt[N],pos[N];
ll solve(int x)
{
    int c1=0,c2=0;
    for(int i=x;i&&c1<=k;i=pre[i])
        a[++c1]=i-pre[i];
    for(int i=x;i<=n&&c2<=k;i=nxt[i])
        b[++c2]=nxt[i]-i;
    ll res=0;
    for(int i=1;i<=c1;i++)
    {
        if(c2>=k-i+1&&k-i+1>=1)
            res+=a[i]*b[k-i+1];
    }
    return res;
}
void del(int x)
{
    pre[nxt[x]]=pre[x];
    nxt[pre[x]]=nxt[x];
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int x;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&x),pos[x]=i;
        ll ans=0;
        for(int i=0;i<=n+1;i++)
            pre[i]=i-1,nxt[i]=i+1;
        pre[0]=0,nxt[n+1]=n+1;
        for(int i=1;i<=n;i++)
        {
            ans+=i*solve(pos[i]);
            del(pos[i]);
        }    
        printf("%lld\n",ans);
    }
    return 0;
} 

 

6058 Kanade's sum 链表维护()

标签:--   i++   can   lld   一个   开始   color   its   scanf   

原文地址:http://www.cnblogs.com/HIKARI1149/p/7273599.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!