hdu 6058 Kanade's sum(链表)
题意:
给你一个n个数的排列,问你全部区间第k大的总和为多少。
题解:
我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x。
我们考虑从小到大枚举xxx,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳kkk次,删除也是O(1)的。
时间复杂度:O(nk)
这题只要是知道能从小到大枚举就好办了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }