HDU - 4417 Super Mario(主席树/线段树+离线)
題目鏈接:點(diǎn)擊查看
題目大意:給出由 n 個(gè)數(shù)的數(shù)列,再給出 m 次查詢,每次查詢需要輸出 [ l , r ] 內(nèi)小于等于 h 的數(shù)有多少個(gè)
題目分析:大晚上睡不著覺(jué)隨便做做題,發(fā)現(xiàn)這個(gè)題目原來(lái)可以用主席樹來(lái)做,又發(fā)現(xiàn)這個(gè)題目去年暑假竟然沒(méi)寫博客,于是補(bǔ)上一發(fā)
線段樹離線的做法就是對(duì)數(shù)列和詢問(wèn)的高度排序,遍歷每個(gè)詢問(wèn),雙指針將小于等于當(dāng)前詢問(wèn)高度的位置都扔到線段樹中,記錄當(dāng)前詢問(wèn)的區(qū)間內(nèi)有多少個(gè)數(shù)即可
主席樹在線做法,有兩種,先說(shuō)一下網(wǎng)上最常見(jiàn)的,就是遍歷每個(gè)位置作為下標(biāo),對(duì)于下標(biāo)維護(hù)可持久化線段樹,每個(gè)權(quán)值線段樹維護(hù)的是高度信息,記錄一下每個(gè)高度出現(xiàn)了多少次,答案顯然就是第 R 個(gè)版本中 [ 1 , h ] 的個(gè)數(shù)減去第 L - 1 個(gè)版本中 [ 1 , h ] 的個(gè)數(shù)了
再說(shuō)一下我自己的做法,我是對(duì)于高度維護(hù)了可持久化線段樹,每個(gè)權(quán)值線段樹維護(hù)的是區(qū)間信息,記錄一下 [ 1 , h ] 內(nèi)的所有數(shù)在區(qū)間上的分布情況,這樣答案就是第 h 個(gè)版本的權(quán)值線段樹中 [ l , r ] 中有多少個(gè)數(shù)了
兩種主席樹的做法時(shí)空復(fù)雜度相同且都是需要進(jìn)行離散化的,但我個(gè)人感覺(jué)自己的做法更好理解一些,更能體現(xiàn)了:主席樹是可持久化線段樹,其中每個(gè)版本的主席樹單獨(dú)拿出來(lái)都是一個(gè)權(quán)值線段樹
代碼:
主席樹:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;struct Node {int l,r;int sum; }tree[N*20];int cnt,root[N];void update(int num,int &k,int l,int r) {tree[cnt++]=tree[k];k=cnt-1;tree[k].sum++;if(l==r)return;int mid=l+r>>1;if(num<=mid)update(num,tree[k].l,l,mid);elseupdate(num,tree[k].r,mid+1,r); }int query(int k,int l,int r,int L,int R)//[l,r]:目標(biāo)區(qū)間,[L,R]:當(dāng)前區(qū)間 {if(R<l||L>r)return 0;if(L>=l&&R<=r)return tree[k].sum;int mid=L+R>>1;return query(tree[k].l,l,r,L,mid)+query(tree[k].r,l,r,mid+1,R); }map<int,vector<int>>mp;vector<int>node;int get_id(int x) {return upper_bound(node.begin(),node.end(),x)-node.begin(); }void discreate() {sort(node.begin(),node.end());node.erase(unique(node.begin(),node.end()),node.end()); }void init() {mp.clear();node.clear();root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1; }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int w;cin>>w;int kase=0;while(w--){init();int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int h;scanf("%d",&h);mp[h].push_back(i);node.push_back(h);}discreate();for(int i=1;i<=node.size();i++)//按照高度建主席樹,每個(gè)高度的前綴和的權(quán)值線段樹代表的是[1,h]內(nèi)的高度在[1,n]上的分布情況 {root[i]=root[i-1];for(int pos:mp[node[i-1]])update(pos,root[i],1,n);}printf("Case %d:\n",++kase);while(m--){int l,r,h;scanf("%d%d%d",&l,&r,&h);l++,r++;printf("%d\n",query(root[get_id(h)],l,r,1,n));}}return 0; }離線+線段樹:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> #include<cmath> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;struct Tree {int l,r,sum; }tree[N<<2];struct Node {int hei,pos;bool operator<(Node a)const{return hei<a.hei;} }a[N];struct node {int hei,l,r,id;bool operator<(node a)const{return hei<a.hei;} }b[N];int ans[N];void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;tree[k].sum=0;if(l==r)return;int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r); }void update(int k,int pos) {if(tree[k].l==tree[k].r){tree[k].sum=1;return;}int mid=(tree[k].l+tree[k].r)>>1;if(mid>=pos)update(k<<1,pos);elseupdate(k<<1|1,pos);tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; }int query(int k,int l,int r) {if(tree[k].r<l||tree[k].l>r)return 0;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].sum;return query(k<<1,l,r)+query(k<<1|1,l,r); }int main() { // freopen("input.txt","r",stdin);int w;cin>>w;int kase=0;while(w--){int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i].hei);a[i].pos=i;}for(int i=1;i<=m;i++){scanf("%d%d%d",&b[i].l,&b[i].r,&b[i].hei);b[i].l++;b[i].r++;b[i].id=i;}build(1,1,n);sort(a+1,a+1+n);sort(b+1,b+1+m);int pos=1;for(int i=1;i<=m;i++){int h=b[i].hei;while(a[pos].hei<=h){update(1,a[pos].pos);pos++;}ans[b[i].id]=query(1,b[i].l,b[i].r);}printf("Case %d:\n",++kase);for(int i=1;i<=m;i++)cout<<ans[i]<<endl;}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的HDU - 4417 Super Mario(主席树/线段树+离线)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: HDU多校5 - 6822 Paperf
- 下一篇: 牛客多校9 - Groundhog Lo