[线段树+离散化+单点查询] HDOJ - 4325 Flowers

来源:互联网 发布:做淘宝怎么做需要哪些 编辑:程序博客网 时间:2024/06/05 01:12

一年没写线段树, 全凭回忆加YY能1A好哈皮..............

很裸的线段树, 就是需要先离散化.

离散化我记得有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 100002struct 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+1add(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);//在这里推不够下...wa1int mid = (a[e].l+a[e].r)>>1;if(p<=mid)//mid算 左边?return query(e<<1, p);elsereturn query(e<<1|1, p);}}int n, m;//m = query timesint 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 100002struct 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+1add(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);//在这里推不够下...wa1int mid = (a[e].l+a[e].r)>>1;if(p<=mid)//mid算 左边?return query(e<<1, p);elsereturn query(e<<1|1, p);}}int n, m;//m = query timesint 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 100002struct 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+1add(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);//在这里推不够下...wa1int mid = (a[e].l+a[e].r)>>1;if(p<=mid)//mid算 左边?return query(e<<1, p);elsereturn query(e<<1|1, p);}}int n, m;//m = query timesint 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);}}}


原创粉丝点击