1. 程式人生 > >【hdu4417】Super Mario——主席樹

【hdu4417】Super Mario——主席樹

== 找到 sca ref cli logs closed event scanf

題目鏈接

題目大意為給定一個長度為n的區間,同時給出m個詢問,每次詢問在區間[l,r]中有多少個數小於或等於k。

同樣考慮用主席樹來維護,每次只需要找到序列b中第一個等於k的數,那麽要求的數必定在b[1]~b[upper_bound(k)]這個範圍內,接下來就像線段樹統計區間個數那樣,若完全包含則直接加上e[rr].sum-e[ll].sum,否則就分兩邊遞歸統計。而建樹什麽的就直接套模板即可。

還要註意一點,原題的區間默認從0開始,因此若像我一樣寫了區間從1開始的記得在query之前將l和r加上1。

最最最最後一點,hdu的老規矩,要註意處理好多組數據。

代碼:

技術分享
#include<cstdio>
#include
<cstring> #include<algorithm> const int N=1e5+5; using namespace std; struct point{ int rt,sum,ls,rs; }e[N*20]; int a[N],b[N],tot,n,m,sz,x,y; void build(int &rt,int le,int ri) { tot++;rt=tot; e[rt].sum=0; if(le==ri)return ; int mid=(le+ri)>>1; build(e[rt].ls,le,mid); build(e[rt].rs,mid
+1,ri); } void up(int &rt,int l,int r,int last,int p) { rt=++tot; e[rt].ls=e[last].ls;e[rt].rs=e[last].rs; e[rt].sum=e[last].sum+1; if(l==r)return; int mid=(l+r)>>1; if(p<=mid)up(e[rt].ls,l,mid,e[last].ls,p); else up(e[rt].rs,mid+1,r,e[last].rs,p); }
int query(int ll,int rr,int l,int r) { if(x>y)return 0; if(x<=l&&y>=r)return e[rr].sum-e[ll].sum; int mid=(l+r)>>1; int ret=0; if(x<=mid)ret+=query(e[ll].ls,e[rr].ls,l,mid); if(y>mid)ret+=query(e[ll].rs,e[rr].rs,mid+1,r); return ret; } void find() { int ll,rr,kk; scanf("%d %d %d",&ll,&rr,&kk); ll++;rr++; x=1;y=upper_bound(b+1,b+1+sz,kk)-(b+1); int an=query(e[ll-1].rt,e[rr].rt,1,sz); printf("%d\n",an); } int main() { int T,ss=1; scanf("%d",&T); while(T--) { tot=0; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); sz=unique(b+1,b+n+1)-(b+1); build(e[0].rt,1,sz); for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+sz,a[i])-b; for(int i=1;i<=n;i++)up(e[i].rt,1,sz,e[i-1].rt,a[i]); printf("Case %d:\n",ss);ss++; while(m--)find(); } return 0; }
hdu4417

【hdu4417】Super Mario——主席樹