1. 程式人生 > >樹狀陣列相關應用之區間包含問題

樹狀陣列相關應用之區間包含問題

區間包含問題

對於一維區間問題一般是採用定一議二的方法 區間外包含問題: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求字首陣列和即可