区间包含问题
对于一维区间问题一般是采用定一议二的方法
区间外包含问题:POJ-2481
对于此问题我们可以先按x升序排序(x值相同,y大的排在前面),保证之后输入的区间的左端必在之前输入区间之内,若x值相等,y降序,则之后输入区间的右端必在之前输入区间之内,那么此题便转化为对y求后缀数组和问题
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <algorithm>
#define MAXSIZE 100005
using namespace std; //使用名称空间std
struct cow
{
int no; //编号
int S, E; //区间
int num; //比其强壮奶牛数量
};
cow arry[MAXSIZE];
int val[MAXSIZE];
int main()
{
bool cmp(cow a, cow b);
bool cmp_no(cow a, cow b);
int lowbit(int x);
void update_1(int val[], int i, int cal, int arry_num);
int sum_pre_1(int val[], int i);
int sum_between_1(int val[], int pre, int last);
int flag;
int begin=0, end=0; //记录区间最大范围,在此范围内构建树状数组
int pre, last; //记录单个区间外的前方和后方奶牛数
while (~scanf("%d",&flag))
{
if (!flag)
break;
memset(val, 0, sizeof(val));
begin = MAXSIZE;
end = 0;
for (int i = 1;i <= flag;i++)
{
arry[i].no = i;
scanf("%d %d", &arry[i].S, &arry[i].E);
begin = begin < arry[i].S ? begin : arry[i].S;
end = end > arry[i].E ? end : arry[i].E;
}
begin++; //区间整体后移(避免区间左端为0的情况)
end++;
//数据输入完成
sort(arry + 1, arry + flag + 1, cmp); //先将左端小的排在前,如果左端相等,再将右端大的排在前
//原数组处理完毕
int temp = 0; //暂存器
for (int i = 1;i <= flag;i++)
{
if (arry[i].S==arry[i - 1].S&&arry[i].E == arry[i - 1].E&&i != 1)
arry[i].num = temp;
else
{
arry[i].num = sum_between_1(val, arry[i].E + 1, end);
temp = arry[i].num;
}
update_1(val, arry[i].S + 1, 1, end);
update_1(val, arry[i].E + 1, 1, end);
}
sort(arry + 1, arry + flag + 1, cmp_no); //数组顺序复原
printf("%d", arry[1].num);
for (int i = 2;i <= flag;i++)
printf(" %d", arry[i].num);
printf("\n");
}
return 0;
}
bool cmp(cow a, cow b)
{//先将左端小的放在前,若左端相等,则将右端大的放在前
if (a.S != b.S)
return a.S < b.S;
else
return a.E > b.E;
}
bool cmp_no(cow a, cow b)
{
return a.no < b.no;
}
int lowbit(int x)
{//返回二进制数最低位的1对应的数值
return x & (-x); //与运算
}
//一维树状数组
void update_1(int val[], int i, int cal, int arry_num)
{//原数组第i个元素加上cal,更新树状数组相关元素,arry_num为原数组的长度
//可直接用于树状数组的建立
for (;i <= arry_num;i += lowbit(i))
val[i] += cal;
}
int sum_pre_1(int val[], int i)
{//求arry数组的前i项和
//val为树状数组地址
int sum = 0;
for (;i > 0;i -= lowbit(i)) //从后向前每次跳一个lowbit
sum += val[i];
return sum;
}
int sum_between_1(int val[], int pre, int last)
{//求原数组arry在区间[pre-last]的和
return sum_pre_1(val, last) - sum_pre_1(val, pre - 1);
}
区间内包含问题则按x降序,y升序排列,对y求前缀数组和即可