hdu 6058 Kanade's sum(链表)

题目链接:hdu 6058 Kanade's sum

题意:

给你一个n个数的排列,问你全部区间第k大的总和为多少。

题解:

我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x。

我们考虑从小到大枚举xxx,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳kkk次,删除也是O(1)的。

时间复杂度:O(nk)

这题只要是知道能从小到大枚举就好办了。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 typedef long long ll;
 5 
 6 const int N=5e5+7;
 7 int t,n,k,a[N],idx[N];
 8 struct Node{int pre,nxt,idx;}node[N];
 9 
10 int main(){
11     scanf("%d",&t);
12     while(t--)
13     {
14         scanf("%d%d",&n,&k);
15         F(i,1,n)
16         {
17             scanf("%d",a+i),idx[a[i]]=i;
18             node[i]=Node{i-1,i+1,i};
19         }
20         node[n+1].idx=n+1;
21         ll ans=0;
22         F(i,1,n)
23         {
24             int l=idx[i],r=idx[i];
25             int cntl=1,cntr=0;
26             while(cntl<k)
27             {
28                 if(node[l].pre==0)break;
29                 cntl++,l=node[l].pre;
30             }
31             while(cntl)
32             {
33                 
34                 while(cntr+cntl>k){cntr--,r=node[r].pre;}
35                 while(cntl+cntr<k)
36                 {
37                     if(node[r].nxt==n+1)break;
38                     cntr++,r=node[r].nxt;
39                 }
40                 if(cntl+cntr==k)
41                 {
42                     int L=node[l].idx-node[node[l].pre].idx;
43                     int R=node[node[r].nxt].idx-node[r].idx;
44                     ans+=1ll*L*R*i;
45                 }
46                 l=node[l].nxt,cntl--;
47             }
48             node[node[idx[i]].pre].nxt=node[idx[i]].nxt;
49             node[node[idx[i]].nxt].pre=node[idx[i]].pre;
50         }
51         printf("%lld\n",ans);
52     }
53     return 0;
54 }
View Code

 

posted @ 2017-08-01 22:54  bin_gege  阅读(106)  评论(0编辑  收藏  举报