HDU4417 Super Mario 线段树离线操作

    xiaoxiao2021-03-26  23

    传送门:HDU4417

    题意:给定n个数,多次询问L到R区间内小于H的数有几个。

    思路:① 先把所有位置的高度都存下来,然后排序,注意保存下标;   ② 把所有询问存下来,然后按照询问的高度进行排序,同注意保存下标;   ③ 对于排序后的每次询问的处理:由于每个位置的高度都已经存了下来并且进行了排序,所以可以按照顺序将每个点的对应下标在线段树中更新为1,直到要插入的位置的高度大于这次询问的高度H;最后处理区间查询,由于刚才已经把小于等于该次查询高度的位置都进行了更新,所以询问的结果就是查询区间中被更新过的叶子节点的个数,也就是区间求和问题。 代码:

    #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> #include<queue> #include<stack> #include<set> #include<vector> #include<map> #define ll long long #define pi acos(-1) #define inf 0x3f3f3f3f #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; typedef pair<int,int>P; const int MAXN=100010; int num[MAXN<<2],ans[MAXN]; struct node{ int l,r,id,h; friend bool operator <(node a,node b) { return a.h<b.h; } }q[MAXN]; struct hight{ int h,id; friend bool operator <(hight a,hight b) { return a.h<b.h; } }a[MAXN]; void pushup(int rt) { num[rt]=num[rt<<1]+num[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { num[rt]=0; return ; } int mid=(l+r)>>1; build(lson); build(rson); pushup(rt); } void update(int id,int l,int r,int rt) { if(l==r) { num[rt]=1;//更新为1 return ; } int mid=(l+r)>>1; if(id<=mid)update(id,lson); else update(id,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return num[rt]; int mid=(l+r)>>1,ans=0; if(L<=mid)ans+=query(L,R,lson); if(mid<R)ans+=query(L,R,rson); return ans; } int main() { int n,m,t; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { scanf("%d%d",&n,&m); build(1,n,1); for(int i=1;i<=n;i++) { scanf("%d",&a[i].h); a[i].id=i; } for(int i=1;i<=m;i++) { scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].h); q[i].id=i; } sort(a+1,a+n+1); sort(q+1,q+m+1); printf("Case %d:\n",cas); for(int i=1,j=1;i<=m;i++) { while(j<=n&&a[j].h<=q[i].h) update(a[j++].id,1,n,1); ans[q[i].id]=query(q[i].l+1,q[i].r+1,1,n,1);//将询问的结果按照原顺序存放起来 } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); } return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-662334.html

    最新回复(0)