hdu 4417 区间内比h小的数 划分树

二分查找最近一个比h小的数

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<queue>
  7 using namespace std;
  8 #define for0n for(i=0;i<n;i++)
  9 #define for1n for(i=1;i<=n;i++)
 10 #define for0m for(i=0;i<m;i++)
 11 #define for1m for(i=1;i<=m;i++)
 12 #define cl(a) memset(a,0,sizeof(a))
 13 #define w12 while(scanf("%d%d",&n,&m)!=EOF)
 14 #define s12 scanf("%d%d",&n,&m);
 15 #define sa scanf("%d",a[i]);
 16 #define sb scanf("%d",b[i]);
 17 #define qq printf("*****\n");
 18 const int maxn=1005;
 19 int n,m,tt;
 20 const int MAXN = 100010;
 21 int tree[20][MAXN];//表示每层每个位置的值
 22 int sorted[MAXN];//已经排序好的数
 23 int toleft[20][MAXN];//toleft[p][i]表示第i层从1到i有数分入左边
 24 void build(int l,int r,int dep)
 25 {
 26     if(l == r)return;
 27     int mid = (l+r)>>1;
 28     int same = mid - l + 1;//表示等于中间值而且被分入左边的个数
 29     for(int i = l; i <= r; i++) //注意是l,不是one
 30     if(tree[dep][i] < sorted[mid])
 31     same--;
 32     int lpos = l;
 33     int rpos = mid+1;
 34     for(int i = l;i <= r;i++)
 35     {
 36         if(tree[dep][i] < sorted[mid])
 37         tree[dep+1][lpos++] = tree[dep][i];
 38         else if(tree[dep][i] == sorted[mid] && same > 0)
 39         {
 40             tree[dep+1][lpos++] = tree[dep][i];
 41             same--;
 42         }
 43         else
 44         tree[dep+1][rpos++] = tree[dep][i];
 45         toleft[dep][i] = toleft[dep][l-1] + lpos - l;
 46     }
 47     build(l,mid,dep+1);
 48     build(mid+1,r,dep+1);
 49 }
 50 //查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间
 51 int query(int L,int R,int l,int r,int dep,int k)
 52 {
 53     if(l == r)return tree[dep][l];
 54     int mid = (L+R)>>1;
 55     int cnt = toleft[dep][r] - toleft[dep][l-1];
 56     if(cnt >= k)
 57     {
 58         int newl = L + toleft[dep][l-1] - toleft[dep][L-1];
 59         int newr = newl + cnt - 1;
 60         return query(L,mid,newl,newr,dep+1,k);
 61     }
 62     else
 63     {
 64         int newr = r + toleft[dep][R] - toleft[dep][r];
 65         int newl = newr - (r-l-cnt);
 66         return query(mid+1,R,newl,newr,dep+1,k-cnt);
 67     }
 68 }
 69 int solve(int n,int s,int t,int h)
 70 {
 71     int l=1;
 72     int r=(t-s)+1;
 73     int ans=0;
 74     while(l<=r)
 75     {
 76         int mid=((l+r)>>1);
 77         int tp=query(1,n,s,t,0,mid);
 78         if(tp<=h)
 79         {
 80             ans=mid;
 81             l=mid+1;
 82         }
 83         else r=mid-1;
 84     }
 85     return ans;
 86 }
 87 int main()
 88 {
 89     #ifndef ONLINE_JUDGE
 90     freopen("1.in","r",stdin);
 91     #endif
 92     int i,j,k,h;
 93     scanf("%d",&tt);
 94     int ca=0;
 95     while(tt--)
 96     {
 97         ca++;
 98         s12;
 99         memset(tree,0,sizeof(tree));
100         for(i = 1;i <= n;i++)
101         {
102             scanf("%d",&tree[0][i]);
103             sorted[i] = tree[0][i];
104         }
105         sort(sorted+1,sorted+n+1);
106         build(1,n,0);
107         int s,t,k;
108         printf("Case %d:\n",ca);
109         while(m--)
110         {
111             scanf("%d%d%d",&s,&t,&h);
112             s++;
113             t++;
114             printf("%d\n",solve(n,s,t,h));
115         }
116     }
117     return 0;
118 }
时间: 2024-08-25 08:28:18

hdu 4417 区间内比h小的数 划分树的相关文章

hdu 4417 区间内比h小的数 线段树

题意求区间内比h小的数的个数 将所有的询问离线读入之后,按H从小到大排序.然后对于所有的结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,然后就是一个区间和. 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using names

hdu 2665 Kth number (poj 2104 K-th Number) 划分树

划分树的基本功能是,对一个给定的数组,求区间[l,r]内的第k大(小)数. 划分树的基本思想是分治,每次查询复杂度为O(log(n)),n是数组规模. 具体原理见http://baike.baidu.com/link?url=vIUKtsKYx7byeS2KCOHUI14bt_0sdHAa9BA1VceHdGsTv5jVq36SfZgBKdaHYUGqIGvIGrE_aJtqy0D0b1fCoq 个人感觉看代码是最好的学习方法. #include <cstdio> #include <c

主席树(区间第k小的数)

题目链接: https://www.luogu.org/problem/P3834 首先要离散化,然后主席树模板. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mid (l+r)/2 5 using namespace std; 6 7 const int N = 200010; 8 int n, q, m, cnt = 0; 9 int a[N], b[N], T[N];

COGS 930. [河南省队2012] 找第k小的数 主席树

主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 #define MAX 2000005 using namespace std; int sum[MAX],l[MAX],mid[MAX],r[MAX],a[MAXN],b[MAXN],n,m,sz,size,root[MAXN],cnt; void build(int &x,int z,int y

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

cogs930.[河南省队2012] 找第k小的数

930. [河南省队2012] 找第k小的数 ★★★   输入文件:kth.in   输出文件:kth.out   简单对比 时间限制:1 s   内存限制:128 MB 题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M.第二行N个数,表示序列A1,A2,...,AN.紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj

【划分树+二分】HDU 4417 Super Mario

第一次 耍划分树.. . 模板是找第k小的 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <queue> #include &l

Luogu P1923 求第k小的数

Luogu P1923 求第k小的数 一看这题,静态查询区间第$k$小的数,不就是可持久化线段树(主席树)的模板题吗?!(误) 直接把主席树的板子打上来?: #include<bits/stdc++.h> #define N 200010 #define mid ((l+r)>>1) using namespace std; int n,m,l,r,k,ans,id,siz; int a[N],b[N]; struct segmenttree { int ls,rs,sum,roo

hdu 4417 Super Mario(离线树状数组|划分树)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2584    Accepted Submission(s): 1252 Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping a