POJ 2481 树状数组 区间覆盖(POJ2352 Stars 的变形题)(线段化点)


0)学会将题目情景转化为自己熟悉的结构或模型。

题目大意:

        每个奶牛有自己的一个区间,求每个奶牛的区间所覆盖的子区间个数(注意,真子集,相等的不算),按照输入的顺序输出。


转化:

        要学会将题目情景转化为自己熟悉的模型或结构上。把每个区间的左端x值作为点的x坐标,右端x值作为点的y坐标,就可以把所有区间转化为一个二维坐标图上的点集,而此时每个点左上方的点(同Stars那道题目一样不包括自身)的个数,就是每个区间所覆盖的子区间的个数(对应题目要求,这里或许可以再变形)。


同POJ2481 Stars:

       不同的是,先线段化点,并对输入的数据进行预处理,即先按y从大到小,y相等的则按x从小到大,以保证,后用来更新树状数组的点不会在先被使用的点的左上方,每输入一个点,则输出该点左上方的点的个数,然后更新树状数组,再输入下一个点。

        还记得01背包问题有二维数组转化为一维数组吗,有点相同的思想,这里只用x来做数组的下标,而y则从大到小输入,一边记录各个点的左上方点的个数,一边继续更新树状数组,而树状数组不再对之前的点有可查询性,只保证当前点的可查询性,比如出现这样的点集:(0,3)(1,2)(2,3),更新顺序是,先返回(0,3)左上方的点的个数,然后更新x>=0的所有点,返回(2,3)左上方的点的个数,然后更新x>=2所有的点,返回(1,2)左上方的点的个数,然后更新x>=1的所有的点,这时,x=2的点也会被+1,但因为(2,3)左上方的点已经被记忆到另一个数组或者输出,所以树状数组也不需要再对这个点的左上方有多少点保持记忆,而只是记录当前更新点(1,2)以及其他所有x>=1,y<=2的后面即将输入的点的左上方的当前点的个数。(所以让点按照y从大到小的顺序输入,以保证后用来更新树状数组的点不会在先被使用的点的左上方,所以用哪个点更新就可以确保此时返回的所用的当前点的左上方的点个数是正确的,是不会再增加的。)


1)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;
const int maxn=100010;
int n;
struct Qujian{
    int l;//该区间左端,每个区间化成一个点以后,左端值就是该点x值
    int r;//该区间右端,化点后,右端值就是该点y值
    int id;//输入次序
    //int v;
}qujian[maxn];
int stars[maxn];//相当于树状数组的c数组(树状数组的a数组a[x]中,x就是点的x坐标,每个点出现的次数就是a[x])
int value[maxn];//区间化为点后,对应id(输入次序)的点的左上方点的个数
bool cmp1(const Qujian a,const Qujian b){
    if(a.r>b.r)
        return 1;
    else if(a.r==b.r&&a.l<b.l){
        return 1;
    }
    else
        return 0;
}
bool cmp2(const Qujian a,const Qujian b){
    return a.id<b.id;
}
int Sum(int x){
    int res=0;
    while(x>0){
        res+=stars[x];
        x-=(x&(-x));
    }
    return res;
}
void Add(int x,int cou){
    while(x<=maxn){
        stars[x]+=cou;
        x+=(x&(-x));
    }
    return ;
}
int main()
{
    while(~scanf("%d",&n)&&n!=0){
        memset(qujian,0,sizeof(qujian));
        memset(stars,0,sizeof(stars));
        memset(value,0,sizeof(value));
        int l;
        int r;
        for(int i=0;i<n;i++){
            scanf("%d%d",&l,&r);
            qujian[i].id=i;
            qujian[i].l=l+1;
            qujian[i].r=r+1;//保证区间的位置从1开始而不会是0
        }
        sort(qujian,qujian+n,cmp1);//y从大到小,如果y相等则x从小到大,保证后出现的点不会在先出现的点的左上方,所以可以按这个顺序一边更新树状数组,一边求得各个点左上方有多少个点并记录下来
        int cou=1;//记录每个点出现的次数
        for(int i=0;i<n;i++){
            value[qujian[i].id]=Sum(qujian[i].l);//返回坐标为l的点的左上方点的个数(不包括自己),所以先返回再加自己的点进去
            if(i+1<n){
                if(qujian[i+1].l==qujian[i].l&&qujian[i+1].r==qujian[i].r){//注意,x,y,两个方向上的坐标都要保证相等,如果只看x坐标,那么就把y不同x相同的点误认为是同一个点了。
                    cou++;//碰到重复区间/相同点,则记录出现次数,等到最后一个进入并且返回其左上方个数之后,再一次性把这些点全部加入
                }
                else{
                    Add(qujian[i].l,cou);
                    cou=1;
                }
            }
            else if(i+1==n){
                Add(qujian[i].l,cou);
            }
        }
        //sort(qujian,qujian+n,cmp2);
        for(int i=0;i<n-1;i++){
            cout<<value[i]<<" ";
        }
        cout<<value[n-1]<<endl;
    }
    return 0;
}

2)

Description

Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good. 

Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John's N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E]. 

But some cows are strong and some are weak. Given two cows: cow  i and cow  j, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cow  i is stronger than cow  j

For each cow, how many cows are stronger than her? Farmer John needs your help!

Input

The input contains multiple test cases. 
For each test case, the first line is an integer N (1 <= N <= 10  5), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 10  5) specifying the start end location respectively of a range preferred by some cow. Locations are given as distance from the start of the ridge. 

The end of the input contains a single 0.

Output

For each test case, output one line containing n space-separated integers, the i-th of which specifying the number of cows that are stronger than cow i

Sample Input

3
1 2
0 3
3 4
0

Sample Output

1 0 0

Hint

Huge input and output,scanf and printf is recommended.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ 2182是一道使用树状数组解决的目,目要求对给定的n个数进行排序,并且输出每个数在排序后的相对位置。树状数组是一种用来高效处理前缀和问的数据结构。 根据引用中的描述,我们可以通过遍历数组a,对于每个元素a[i],可以使用二分查找找到a到a[i-1]中小于a[i]的数的个数。这个个数就是它在排序后的相对位置。 代码中的query函数用来求前缀和,add函数用来更新树状数组。在主函数中,我们从后往前遍历数组a,通过二分查找找到每个元素在排序后的相对位置,并将结果存入ans数组中。 最后,我们按顺序输出ans数组的元素即可得到排序后的相对位置。 参考代码如下: ```C++ #include <iostream> #include <cstdio> using namespace std; int n, a += y; } } int main() { scanf("%d", &n); f = 1; for (int i = 2; i <= n; i++) { scanf("%d", &a[i]); f[i = i & -i; } for (int i = n; i >= 1; i--) { int l = 1, r = n; while (l <= r) { int mid = (l + r) / 2; int k = query(mid - 1); if (a[i > k) { l = mid + 1; } else if (a[i < k) { r = mid - 1; } else { while (b[mid]) { mid++; } ans[i = mid; b[mid = true; add(mid, -1); break; } } } for (int i = 1; i <= n; i++) { printf("%d\n", ans[i]); } return 0; } ``` 这段代码使用了树状数组来完成目要求的排序功能,其中query函数用来求前缀和,add函数用来更新树状数组。在主函数中,我们从后往前遍历数组a,通过二分查找找到每个元素在排序后的相对位置,并将结果存入ans数组中。最后,我们按顺序输出ans数组的元素即可得到排序后的相对位置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [poj2182Lost Cows——树状数组快速查找](https://blog.csdn.net/aodan5477/article/details/102045839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [poj_2182 线段树/树状数组](https://blog.csdn.net/weixin_34138139/article/details/86389799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值