1. 程式人生 > >hdu 6058 Kanade's sum(鏈表)

hdu 6058 Kanade's sum(鏈表)

php blank pri 暴力 splay href .cn 每次 n)

題目鏈接: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

hdu 6058 Kanade's sum(鏈表)