题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 , 线段树(或树状数组) + 离线处理
最近看了几道线段树的题都是需要离线处理数据的,正好这块比较手生,就练练了。
这道题主要的地方就是离线处理数据,具体想法:
① 先把所有位置的高度都存下来,然后排序,注意保存下标;
② 把所有询问存下来,然后按照询问的高度进行排序,同注意保存下标;
③ 对于排序后的每次询问的处理:由于每个位置的高度都已经存了下来并且进行了排序,所以可以按照顺序将每个点插入到线段树的对应位置(保存的下标),并更新线段树,直到要插入的位置的高度大于这次询问的高度H;最后处理区间查询,由于刚才已经把小于等于该次查询高度的位置都已经插入到了线段树中,所以询问的结果就是查询区间中被更新过的叶子节点的个数,也就是区间求和问题。
#include <iostream> #include <cstdio> #include <vector> #include <cmath> #include <string> #include <string.h> #include <algorithm> using namespace std; #define LL __int64 #define eps 1e-8 #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int MOD = 10000007; const int maxn = 100000 + 5; const int N = 15; struct Node { //每个节点的信息 int h , pos; bool operator < (const Node tmp) const { return h < tmp.h; } } a[maxn]; struct Section { //每次查询的区间信息 int L , R , H; int index; bool operator < (const Section tmp) const { return H < tmp.H; } } s[maxn]; int cnt[maxn << 2] , ans[maxn]; void PushUp(int rt) { cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1]; } void build() { memset(cnt , 0 , sizeof(cnt)); } void update(int p , int l , int r , int rt) { if(l == r) { cnt[rt]++; return; } int m = (l + r) >> 1; if(p > m) //找到更新点的位置 update(p , rson); else update(p , lson); PushUp(rt); } int query(int L , int R , int l , int r , int rt) { if(L <= l && R >= r) { return cnt[rt]; } int m = (l + r) >> 1; if(L > m) return query(L , R , rson); else if(R <= m) return query(L , R , lson); else return query(L , R , lson) + query(L , R , rson); } int main() { int T , i , j , n , m; cin >> T; for(int k = 1 ; k <= T ; k++) { build(); printf("Case %d:\n" , k); scanf("%d %d" , &n , &m); for(i = 1 ; i <= n ; i++) { scanf("%d" , &a[i].h); a[i].pos = i; } for(i = 1 ; i <= m ; i++) { scanf("%d %d %d" , &s[i].L , &s[i].R , &s[i].H); s[i].index = i; } sort(a + 1 , a + n + 1); sort(s + 1 , s + m + 1); for(i = j = 1 ; i <= m ; i++) { //这里就是上面的③ while(a[j].h <= s[i].H && j <= n) { update(a[j++].pos , 1 , n , 1); } ans[s[i].index] = query(s[i].L + 1 , s[i].R + 1 , 1 , n , 1); } for(i = 1 ; i <= m ; i++) printf("%d\n" , ans[i]); } return 0; }
此题还可以用划分树来做,并且特别快,可惜我没学~
时间: 2024-12-28 16:10:20