主席樹鋪墊——總區間第k小
阿新 • • 發佈:2020-07-17
題目描述(口糊)
先給定一個長度為n的數列,然後給m次操作,每次輸入b,求第b小的數。
樣例輸入
5
7 4 10 9 23
5
1
2
3
4
5
樣例輸出
4
7
9
10
23
資料範圍及溫馨提示
1e9 大家一定要用線段樹做這道題啊!
建議大家在認真閱讀一下逆序對的題解
於是這裡我們只需要把query改一下其實就可以了。
int query(int k,int cnt) { if(node[k].l==node[k].r) return node[k].l; if(cnt<=node[node[k].son[0]].cnt) return query(node[k].son[0],cnt); else return query(node[k].son[1],cnt-node[node[k].son[0]].cnt); }
其他都一樣,我用的是動態開點。
整體程式碼如下:
#include<bits/stdc++.h> using namespace std; const int N=1000005; struct sd{ int son[2]; long long l,r,cnt; }node[N]; int n; int cnt=1; long long ans; void update(int k) { node[k].cnt=node[node[k].son[0]].cnt+node[node[k].son[1]].cnt; } void modify(int k,int val) { if(node[k].l==node[k].r&&node[k].l==val) { node[k].cnt++; return; } int mid=node[k].l+node[k].r;mid/=2; if(node[k].son[0]==0) { cnt++; node[k].son[0]=cnt; node[cnt].l=node[k].l;node[cnt].r=mid; } if(node[k].son[1]==0) { cnt++; node[k].son[1]=cnt; node[cnt].l=mid+1;node[cnt].r=node[k].r; } if(val>mid) { modify(node[k].son[1],val); } else { modify(node[k].son[0],val); } update(k); } /*long long query(int k,int ql,int qr) { if(k==0) return 0; if(node[k].l==ql&&node[k].r==qr) { return node[k].cnt; } else { int mid=(node[k].l+node[k].r)/2; if(qr<=mid) return query(node[k].son[0],ql,qr); else if(ql>mid) return query(node[k].son[1],ql,qr); else { return query(node[k].son[0],ql,mid)+query(node[k].son[1],mid+1,qr); } } }*/ long long query(int k,int val) { if(node[k].l==node[k].r) return node[k].l; if(val>node[node[k].son[0]].cnt)return query(node[k].son[1],val-node[node[k].son[0]].cnt); else query(node[k].son[0],val); } int main() { std::ios::sync_with_stdio(false); node[1].l=1; node[1].r=1e9+7; int n,sth; cin>>n; ans=0; for(int i=1;i<=n;++i) { cin>>sth; modify(1,sth); } int m; cout<<"Please input the number:"; cin>>m; int v; for(int i=1;i<=n;++i) { cin>>v; cout<<"The "<<v<<"th max number is: "; cout<<query(1,v)<<endl; } }
總結
其實這個東西可以支援邊增加數,邊查詢第n小,這樣總比,加一個數sort一遍要快太多了。然後當你自己已經能夠熟練地敲這篇程式碼的時候,我相信你也很快也可以理解到主席樹的精髓!!!