[线段树+离散化+单点查询] HDOJ - 4325 Flowers
2012-08-01 21:18
155 查看
一年没写线段树, 全凭回忆加YY能1A好哈皮..............
很裸的线段树, 就是需要先离散化.
离散化我记得有lower_bound这种东西, 但是想不起来怎么用了...所以这里是YY了用了个map然后O(n)循环进行离散值对应...
预备:
1/ STL - unique, 接受两个指针(第三个参数为可选自定义相等比较器, 相等返回true), 实现呢就是从头到尾扫一遍, 利用相等元素相邻(若不满足则要先sort). 将区间重复的元素都放到末尾, 返回前面不重复区间的最后一个元素地址.
返回下确界元素的地址. 目测用的二分.
下面给出利用unique / lower_bound 来进行离散化的部分代码:
代码(原先):
代码(lower_bound):
代码(upper_bound):
很裸的线段树, 就是需要先离散化.
离散化我记得有lower_bound这种东西, 但是想不起来怎么用了...所以这里是YY了用了个map然后O(n)循环进行离散值对应...
预备:
1/ STL - unique, 接受两个指针(第三个参数为可选自定义相等比较器, 相等返回true), 实现呢就是从头到尾扫一遍, 利用相等元素相邻(若不满足则要先sort). 将区间重复的元素都放到末尾, 返回前面不重复区间的最后一个元素地址.
template <class ForwardIterator> ForwardIterator unique ( ForwardIterator first, ForwardIterator last ) { ForwardIterator result=first; while (++first != last) { if (!(*result == *first)) // or: if (!pred(*result,*first)) for the pred version *(++result)=*first; } return ++result; }2/ STL - lower_bound, 接受两个指针跟要找的值(第四个可选参数为自定义小于比较器, 小于返回true),用于在有序的区间中查找首个不小于(小于等于)某值的元素(大于等于某值),
返回下确界元素的地址. 目测用的二分.
template <class ForwardIterator, class T> ForwardIterator lower_bound ( ForwardIterator first, ForwardIterator last, const T& value ) { ForwardIterator it; iterator_traits<ForwardIterator>::distance_type count, step; count = distance(first,last); while (count>0) { it = first; step=count/2; advance (it,step); if (*it<value) // or: if (comp(*it,value)), for the comp version { first=++it; count-=step+1; } else count=step; } return first; }
下面给出利用unique / lower_bound 来进行离散化的部分代码:
sort(all, all+idx); int tot = unique(all, all+idx) - all; build(1, tot, 1); ... int x = lower_bound(all, all+tot, st[i]) - all; int y = lower_bound(all, all+tot, en[i]) - all;简言之就是, 用unique来剔除重复元素, 用lower_bound来查找元素位置(unique后的区间已经是不重复的了, 所以只是查找而已, 所以你甚至可以用upper_bound, 只不过upper_bound返回的是大于value()不包含等于, 所以要用 upper_bound(...)-1, 等价于 lower_bound(...) ).
代码(原先):
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<map> #include<algorithm> using namespace std; int Rint() { int x; scanf("%d", &x); return x; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) #define bug(s) cout<<#s<<"="<<s<<" " #define MAXN 100002 struct node { int l, r, v; int add; //lazy-add }a[MAXN*2*4]; //1-th //10^9离散化, 10^5条线段, 最多可能产生 2*10^5个点 void pushdown(int e) { if(a[e].add) { if(a[e].l != a[e].r) //若不是叶子, 则下推 { a[e<<1].add += a[e].add; a[e<<1|1].add += a[e].add; //pushdown(e<<1); //不能递归下推, 不然也不是lazy了 //pushdown(e<<1|1); } a[e].v += a[e].add; a[e].add = 0; } } void build(int l, int r, int e) { a[e].l = l; a[e].r = r; a[e].v = a[e].add = 0; if(l == r) { return; } else { int mid = (l+r)>>1; build(l, mid, e<<1); build(mid+1, r, e<<1|1); } } void add(int l, int r, int e) { //if(l!=r) //不用到叶子节点, 不然延迟处理就没意义了, 效率退化必TLE~- - if(l<=a[e].l && a[e].r<=r) { a[e].add += 1; } else { int mid = (a[e].l+a[e].r)>>1; if(l<=mid) add(l, r, e<<1); if(mid+1<=r) //注意是 mid+1 add(l, r, e<<1|1); } } int query(int e, int p) { pushdown(e); if(a[e].l == p && a[e].r == p) { return a[e].v; } else { //pushdown(e); //在这里推不够下...wa1 int mid = (a[e].l+a[e].r)>>1; if(p<=mid) //mid算 左边? return query(e<<1, p); else return query(e<<1|1, p); } } int n, m; //m = query times int st[MAXN], en[MAXN]; int q[MAXN]; int all[MAXN*3]; int idx; map<int, int> tolow; // e.g. tolow[234] = 1; int main() { int t = Rint(); FOR(T, 1, t) { tolow.clear(); idx = 0; printf("Case #%d:\n", T); n = Rint(); m = Rint(); REP(n) { st[i] = Rint(); en[i] = Rint(); all[idx++] = st[i]; all[idx++] = en[i]; } REP(m) { q[i] = Rint(); all[idx++] = q[i]; } sort(all, all+idx); int rank = 1; REP(idx) { int v = all[i]; if(tolow[v]) continue; tolow[v] = rank++; //离散后的值从1开始 } int tot = tolow.size(); build(1, tot, 1); REP(n) { add(tolow[st[i]], tolow[en[i]], 1); } REP(m) { int ans = query(1, tolow[q[i]]); printf("%d\n", ans); } } }
代码(lower_bound):
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<map> #include<algorithm> using namespace std; int Rint() { int x; scanf("%d", &x); return x; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) #define bug(s) cout<<#s<<"="<<s<<" " #define MAXN 100002 struct node { int l, r, v; int add; //lazy-add }a[MAXN*2*4]; //1-th //10^9离散化, 10^5条线段, 最多可能产生 2*10^5个点 void pushdown(int e) { if(a[e].add) { if(a[e].l != a[e].r) //若不是叶子, 则下推 { a[e<<1].add += a[e].add; a[e<<1|1].add += a[e].add; //pushdown(e<<1); //不能递归下推, 不然也不是lazy了 //pushdown(e<<1|1); } a[e].v += a[e].add; a[e].add = 0; } } void build(int l, int r, int e) { a[e].l = l; a[e].r = r; a[e].v = a[e].add = 0; if(l == r) { return; } else { int mid = (l+r)>>1; build(l, mid, e<<1); build(mid+1, r, e<<1|1); } } void add(int l, int r, int e) { //if(l!=r) //不用到叶子节点, 不然延迟处理就没意义了, 效率退化必TLE~- - if(l<=a[e].l && a[e].r<=r) { a[e].add += 1; } else { int mid = (a[e].l+a[e].r)>>1; if(l<=mid) add(l, r, e<<1); if(mid+1<=r) //注意是 mid+1 add(l, r, e<<1|1); } } int query(int e, int p) { pushdown(e); if(a[e].l == p && a[e].r == p) { return a[e].v; } else { //pushdown(e); //在这里推不够下...wa1 int mid = (a[e].l+a[e].r)>>1; if(p<=mid) //mid算 左边? return query(e<<1, p); else return query(e<<1|1, p); } } int n, m; //m = query times int st[MAXN], en[MAXN]; int q[MAXN]; int all[MAXN*3]; int idx; map<int, int> tolow; // e.g. tolow[234] = 1; int main() { int t = Rint(); FOR(T, 1, t) { tolow.clear(); idx = 0; printf("Case #%d:\n", T); n = Rint(); m = Rint(); REP(n) { st[i] = Rint(); en[i] = Rint(); all[idx++] = st[i]; all[idx++] = en[i]; } REP(m) { q[i] = Rint(); all[idx++] = q[i]; } sort(all, all+idx); int tot = unique(all, all+idx) - all; build(1, tot, 1); REP(n) { int x = lower_bound(all, all+tot, st[i]) - all + 1; int y = lower_bound(all, all+tot, en[i]) - all + 1; add(x, y, 1); } REP(m) { int x = lower_bound(all, all+tot, q[i]) - all + 1; int ans = query(1, x); printf("%d\n", ans); } } }
代码(upper_bound):
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<string> #include<vector> #include<map> #include<algorithm> using namespace std; int Rint() { int x; scanf("%d", &x); return x; } #define FOR(i, a, b) for(int i=(a); i<=(b); i++) #define FORD(i,a,b) for(int i=(a);i>=(b);i--) #define REP(x) for(int i=0; i<(x); i++) typedef long long int64; #define INF (1<<30) #define bug(s) cout<<#s<<"="<<s<<" " #define MAXN 100002 struct node { int l, r, v; int add; //lazy-add }a[MAXN*2*4]; //1-th //10^9离散化, 10^5条线段, 最多可能产生 2*10^5个点 void pushdown(int e) { if(a[e].add) { if(a[e].l != a[e].r) //若不是叶子, 则下推 { a[e<<1].add += a[e].add; a[e<<1|1].add += a[e].add; //pushdown(e<<1); //不能递归下推, 不然也不是lazy了 //pushdown(e<<1|1); } a[e].v += a[e].add; a[e].add = 0; } } void build(int l, int r, int e) { a[e].l = l; a[e].r = r; a[e].v = a[e].add = 0; if(l == r) { return; } else { int mid = (l+r)>>1; build(l, mid, e<<1); build(mid+1, r, e<<1|1); } } void add(int l, int r, int e) { //if(l!=r) //不用到叶子节点, 不然延迟处理就没意义了, 效率退化必TLE~- - if(l<=a[e].l && a[e].r<=r) { a[e].add += 1; } else { int mid = (a[e].l+a[e].r)>>1; if(l<=mid) add(l, r, e<<1); if(mid+1<=r) //注意是 mid+1 add(l, r, e<<1|1); } } int query(int e, int p) { pushdown(e); if(a[e].l == p && a[e].r == p) { return a[e].v; } else { //pushdown(e); //在这里推不够下...wa1 int mid = (a[e].l+a[e].r)>>1; if(p<=mid) //mid算 左边? return query(e<<1, p); else return query(e<<1|1, p); } } int n, m; //m = query times int st[MAXN], en[MAXN]; int q[MAXN]; int all[MAXN*3]; int idx; map<int, int> tolow; // e.g. tolow[234] = 1; int main() { int t = Rint(); FOR(T, 1, t) { tolow.clear(); idx = 0; printf("Case #%d:\n", T); n = Rint(); m = Rint(); REP(n) { st[i] = Rint(); en[i] = Rint(); all[idx++] = st[i]; all[idx++] = en[i]; } REP(m) { q[i] = Rint(); all[idx++] = q[i]; } sort(all, all+idx); int tot = unique(all, all+idx) - all; build(1, tot, 1); REP(n) { int x = upper_bound(all, all+tot, st[i]) - all; //upper_bound: 查找首个大于value(或comp比较为真)的上确界元素 int y = upper_bound(all, all+tot, en[i]) - all; add(x, y, 1); } REP(m) { int x = upper_bound(all, all+tot, q[i]) - all; int ans = query(1, x); printf("%d\n", ans); } } }
相关文章推荐
- [线段树+离散化+单点查询] HDOJ - 4325 Flowers
- hdoj 4325 Flowers 【线段树 + 离散化】【区间更新 单点查询】
- HDOJ 4325 Flowers 【线段树 离散化 区间更新 单点查询】
- hdoj 4325 Flowers【线段树+离散化】
- hdoj--4325--Flowers(线段树+二分)
- HDOJ 题目4325 Flowers(线段树+离散化)
- hdoj--4325--Flowers(线段树+二分)
- HDU 4325 Flowers (线段树+离散化)
- [HDOJ4325]Flowers(树状数组 离散化)
- hdu - 4325- Flowers - 区间更新,单点查询
- hdu 4325 Flowers (树状数组+离散化)
- HDOJ 1556 Color the ball 线段树 : 成段更新 单点查询
- HDU 4325 Flowers(线段树+离散化)
- 2015 UESTC 数据结构专题A题 秋实大哥与小朋友 线段树 区间更新,单点查询,离散化
- Vases and Flowers(线段树+二分+区间修改区间查询)
- hdu -4325-Flowers(离散化 线段树)
- 【洛谷1198 JSOI】最大数 单点更新线段树+区间查询最大值
- hdu 4325 Flowers(区间离散化)
- hdu 4325 Flowers 离散化+线段树 多校联合赛(三) 第六题
- hdu 4325 Flowers (区间处理 离散化)