HDU4417 Super Mario 主席树
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - HDU4417
题意概括
给定一个长度为n的区间,同时给出m个询问,每次询问在区间[l,r]中有多少个数小于或等于k。
题解
几乎是模板题。
我们只需要把query函数随便改改就可以了。
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=100005,S=N*4*20; int T,n,m,root[N],ls[S],rs[S],sum[S],v[N],ha[N],cnt,total; void pushup(int rt){ sum[rt]=sum[ls[rt]]+sum[rs[rt]]; } int build(int le,int ri){ int rt=++total; if (le==ri){ ls[rt]=rs[rt]=sum[rt]=0; return rt; } int mid=(le+ri)>>1; ls[rt]=build(le,mid); rs[rt]=build(mid+1,ri); pushup(rt); return rt; } int update(int rt,int le,int ri,int pos){ int now=++total; if (le==ri){ sum[now]=sum[rt]+1; ls[now]=rs[now]=0; return now; } int mid=(le+ri)>>1; if (pos<=mid) ls[now]=update(ls[rt],le,mid,pos),rs[now]=rs[rt]; else rs[now]=update(rs[rt],mid+1,ri,pos),ls[now]=ls[rt]; pushup(now); return now; } int query(int rt1,int rt2,int le,int ri,int val){ if (ha[ri]<=val) return sum[rt2]-sum[rt1]; if (ha[le]>val) return 0; int mid=(le+ri)>>1; return query(ls[rt1],ls[rt2],le,mid,val)+query(rs[rt1],rs[rt2],mid+1,ri,val); } int main(){ scanf("%d",&T); for (int Case=1;Case<=T;Case++){ printf("Case %d:\n",Case); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&v[i]),ha[i]=v[i]; sort(ha+1,ha+n+1); cnt=1; for (int i=2;i<=n;i++) if (ha[i]!=ha[i-1]) ha[++cnt]=ha[i]; total=0; root[0]=build(1,cnt); for (int i=1;i<=n;i++){ v[i]=lower_bound(ha+1,ha+cnt+1,v[i])-ha; root[i]=update(root[i-1],1,cnt,v[i]); } for (int i=1;i<=m;i++){ int a,b,v; scanf("%d%d%d",&a,&b,&v); printf("%d\n",query(root[a],root[b+1],1,cnt,v)); } } return 0; }