1. 程式人生 > >hdu 4417 Super Mario (主席樹)

hdu 4417 Super Mario (主席樹)

代碼 i++ uil 我們 php amp build iostream sort

鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4417

題意:

給你段長為n的序列,有q個詢問,每次詢問區間[l.r]內有多少個數小於等於k

思路:

之前用分塊寫過類似的,不過為了練習下主席樹,這裏用主席樹寫了下。思路很簡單

離線離散化處理下,每次插入一個數num時,在主席樹上下標num+1,這樣每次詢問[l,r]中有多少個小於k的數的時候,我們只要找下標【1,k】的區間第R次修改後的總和減去第L-1次修改後的總值就可以得到了

實現代碼:

#include<iostream>
#include<cstdio>
#include
<algorithm> using namespace std; const int M = 2e5+10; int ls[M*40],rs[M*40],sum[M*40],a[M],b[M],root[M]; int idx; void build(int &k,int l,int r){ k = ++idx; sum[k] = 0; if(l == r) return ; int mid = (l + r) >> 1; build(ls[k],l,mid); build(rs[k],mid+1,r); }
void update(int old,int &k,int l,int r,int p,int c){ k = ++idx; ls[k] = ls[old]; rs[k] = rs[old]; sum[k] = sum[old] + c; if(l == r) return ; int mid = (l + r) >> 1; if(p <= mid) update(ls[old],ls[k],l,mid,p,c); else update(rs[old],rs[k],mid+1,r,p,c); }
int query(int old,int k,int L,int R,int l,int r){ if(L <= l&&R >= r) return sum[k] - sum[old]; int mid = (l + r) >> 1; int ret = 0; if(L <= mid) ret += query(ls[old],ls[k],L,R,l,mid); if(R > mid) ret += query(rs[old],rs[k],L,R,mid+1,r); return ret; } int l[M],r[M],x[M],cnt; int Find(int x){ int num = lower_bound(b+1,b+1+cnt,x)-b; return num; } int main() { int t,q,n,cas=1; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&q); for(int i = 1;i <= n;i ++) scanf("%d",&a[i]),b[i] = a[i]; for(int i = 1;i <= q;i ++) scanf("%d%d%d",&l[i],&r[i],&x[i]),b[i+n]=x[i]; sort(b+1,b+1+n+q); cnt = unique(b+1,b+1+n+q)-b-1; for(int i = 1;i <= n;i++){ int fx = Find(a[i]); update(root[i-1],root[i],1,cnt,fx,1); } printf("Case %d:\n",cas++); for(int i = 1;i <= q;i ++){ int fx = Find(x[i]); printf("%d\n",query(root[l[i]],root[r[i]+1],1,fx,1,cnt)); } } return 0; }

hdu 4417 Super Mario (主席樹)