POJ2352 Stars & POJ2481 Cows 树状数组的应用

POJ2352

题目链接

Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given star. Astronomers want to know the distribution of the levels of the stars.For example, look at the map shown on the figure above. Level of the star number 5 is equal to 3 (it’s formed by three stars with a numbers 1, 2 and 4). And the levels of the stars numbered by 2 and 4 are 1. At this map there are only one star of the level 0, two stars of the level 1, one star of the level 2, and one star of the level 3.You are to write a program that will count the amounts of the stars of each level on a given map.

Input
The first line of the input file contains a number of stars N (1<=N<=15000). The following N lines describe coordinates of stars (two integers X and Y per line separated by a space, 0<=X,Y<=32000). There can be only one star at one point of the plane. Stars are listed in ascending order of Y coordinate. Stars with equal Y coordinates are listed in ascending order of X coordinate.

Output
The output should contain N lines, one number per line. The first line contains amount of stars of the level 0, the second does amount of stars of the level 1 and so on, the last line contains amount of stars of the level N-1.

1.题目大意是输入一堆坐标,然后y坐标是排好序的,定义了一个“高度”,就是某个星星左下角(包括正左和正下)的星星个数,然后按“高度”有小到大输出每个“高度”的星星个数

2.首先看到这题目觉得很玄乎,似乎看起来挺简单但是无可下手,写了个暴力,但转身一想肯定超时。但是自己似乎掌握的技能里边没有能直接应用到这道题的。去网上看发现都是树状数组的解法,线段树也很少。搞懂树状数组后,发现仍然是一头雾水。树状数组维护的是前缀和或者区间问题,感觉没法去写啊

3.思考了一下午后,终于搞明白了。题目确实和前缀和没关系,但是主要原因是我把思维定性到了维护区间上。接下来仔细想树状数组求前缀和,是从后往前回溯求和。再加上本题的一个重要条件,y已经排好序,也就是我们在前面添加进去的星星y坐标一定满足小于或等于当前的y坐标,然后就是直接找小于等于当前x坐标的已输入星星个数

4.在得出此题解法思路时,脑子还是懵懵的。我们看下图的树状数组,我们维护的数组变成对应x坐标即可。假设我们第一次输入了x=1坐标的星星,那么之后的星星i肯定都满足xi>=1,yi>=y1。然后我们重复加lowbit(i),更新的界限是什么呢?这里需要特别注意,我们可能就直接就按星星个数n来说了。但是我们目的是按lowbit更新后面的t数组维护的星星个数,所以,我们这里的界限应该设成大于等于x坐标的最大值32000。然后就是查询当前x坐标的高度(之前低于它的星星个数),如下图我们查询x=5的“高度”时,我们第一次加的t[5]都懂,接着第二次加的t[4]包含了前面x<=4的所有星星个数。那么此题就迎刃而解了

5.最后强调此类问题的一个易错点,输入的所有坐标都加一,因为树状数组维护的下标没有0,因此都加一并不影响解题

在这里插入图片描述

#include <iostream>
#define lowbit(x) (x&(-x))
using namespace std;

const int maxn=32010;
int t[maxn],ans[maxn];
int n;

void update(int i){
    while(i<=maxn){
        t[i]++;
        i+=lowbit(i);
    }
}

int getSum(int i){
    int res=0;
    for(;i;i-=lowbit(i)){
        res+=t[i];
    }
    return res;
}

int main()
{
    int m,z;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&m,&z);
        m++; //易错
        ans[getSum(m)]++;
        update(m);
    }
    for(int i=0;i<n;i++) printf("%d\n",ans[i]);
    return 0;
}

POJ2481

题目链接

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.

1.题意是每头牛都有一个区间,如果一头牛的的区间是另一头牛区间的真子集,那么另一头牛比这头牛强壮。按输入顺序输出牛群中比每头牛强壮的牛的个数

2.看到这种直接写的题,老想着暴力去交一发,也许以后要学会分析时间复杂度了。显然暴力过不了,那么分析一下问题,很容易发现这种区间的问题在贪心专题那边很多。我们如果将区间的右边界按从大到小降序排列,右边界相同的话把左边界按从小到大排序,那么,画图可知,比每一头牛a强壮的牛b肯定排在a的前面并且sb<sa。但是接下来怎么做,貌似又卡住了

3.不难得知,每一头牛前面有多少si小于当前牛的s那么就有多少比它强壮的牛。再看上一道题,我们就把问题化为了当前值前面区间的值之和,那么仍然是使用树状数组。Stars那道题给我们排好了另一维的序并且给我们说明了思路。而这道题需要我们排序化为一维并想到树状数组求解

4.先按前面说的那样给结构体排序,然后一个个先求解再更新树状数组。注意到我们需要按输入顺序输出,那么结构体应该保存输入的id。然后我们注意到s可能等于0,在处理时仍然是每个s都加一,接着是更新的界限,和上题一样,仍然是s的最大值。再一个最容易忽略的是如果当前的s和e都和前一个相等,我们就不能查询和更新了,直接把之前的保存答案对应id赋值

#include <iostream>
#include <cstring>
#include <algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long ll;
const int N=1e5+10;
struct tree{
    int s,e,id;
}a[N];
int t[N],ans[N];
int n;

bool cmp(tree &x,tree &y){
    if(x.e==y.e) return x.s<y.s;
    return x.e>y.e;
}

void update(int i){
    while(i<=N){
        t[i]++;
        i+=lowbit(i);
    }
}

int solve(int i){
    int ans=0;
    for(;i;i-=lowbit(i)){
        ans+=t[i];
    }
    return ans;
}

int main()
{
    int temp;
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        memset(t,0,sizeof(t));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].s,&a[i].e);
            a[i].id=i;
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++){
            if(a[i].s==a[i-1].s&&a[i].e==a[i-1].e) ans[a[i].id]=ans[a[i-1].id];
            else ans[a[i].id]=solve(a[i].s+1);
            update(a[i].s+1);
        }
        for(int i=1;i<=n;i++){
            if(i!=n) printf("%d ",ans[i]);
            else printf("%d\n",ans[i]);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值