题目链接:POJ 2481 Cows
发现这两个题目都跟求逆序数有着异曲同工之妙,通过向树状数组中插入点的位置,赋值为1,或者++,然后通过求和来判断比当前 点 ”小“ 的有多少点。
Cows需要自己排序, Stars题目已经给排好序。
POJ 2352 Stars
题目大意为在二维坐标上给出一些星星的坐标,求某一个星星左方,下方,左下方的星星个数。题目已经把星星按照Y坐标从小到大,X从小到大排序。因此,在每次对一个星星进行统计时,之前出现过的星星,只要X坐标比其小,则必在其左,下,左下方。
树状数组储存X的坐标。 就像 求逆序数 的方法一样, 统计有多少之前的星星的X坐标小于当前的X坐标。
需要注意的是 X 坐标的范围是32000 ,所以树状数组要开到32000 而不是节点数15000。
【源代码】
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 32010;
int s[maxn];
int level[maxn];
int n;
int lowbit(int x){
return x&(-x);
}
int sum(int x){
int ans = 0;
for(int i=x;i>0;i-=lowbit(i)){
ans+=s[i];
}
return ans;
}
void add(int x){
for(int i=x;i<=maxn;i+=lowbit(i)){
s[i]++;
}
}
int main(){
while(scanf("%d",&n)!=EOF){
int a,b;
memset(s,0,sizeof(s));
memset(level,0,sizeof(level)); //初始化
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
++a; //希望节点从1开始而不是0 ,所以++
level[sum(a)]++; //直接将统计的数量当做level的下标
add(a); //添加节点
}
for(int i=0;i<n;i++){
printf("%d\n",level[i]);
}
}
return 0;
}
POJ 2481 Cows
和上一题类似的思想,不过需要手动排序。具体怎么做只要上一题弄懂了应该很容易写出来。
坑点在于可能出现相同的区间,在统计的时候简单处理一下就好。
【源代码】
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
const int maxn = 100100;
struct node{
int st,end;int id;
}cow[maxn];
int s[maxn];
int level[maxn];
int lowbit(int x){ return x&(-x);}
void add(int x){
for(int i=x;i<=maxn;i+=lowbit(i))
s[i]++;
}
int sum(int x){
int ans=0;
for(int i=x;i>0;i-=lowbit(i)){
ans+=s[i];
}
return ans;
}
bool cmp(const node&a, const node&b){
if(a.end==b.end)
return a.st<b.st;
return a.end>b.end;
}
int main(){
while(scanf("%d",&n)!=EOF&&n){
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++){
scanf("%d%d",&cow[i].st,&cow[i].end);
cow[i].st++; //希望节点从1开始 而不是0 ,所以++
cow[i].id=i;
}
sort(cow+1,cow+n+1,cmp);
for(int i=1;i<=n;i++){
if(i>1&&cow[i].st==cow[i-1].st&&cow[i].end==cow[i-1].end){ //判重
level[cow[i].id]=level[cow[i-1].id];
}
else
level[cow[i].id]=sum(cow[i].st);
add(cow[i].st);
}
for(int i=1;i<=n;i++)
{
if(i!=1)
printf(" ");
printf("%d",level[i]);
}
puts("");
}
return 0;
}